xref: /OK3568_Linux_fs/external/xserver/xkb/maprules.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /************************************************************
2*4882a593Smuzhiyun  Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc.
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun  Permission to use, copy, modify, and distribute this
5*4882a593Smuzhiyun  software and its documentation for any purpose and without
6*4882a593Smuzhiyun  fee is hereby granted, provided that the above copyright
7*4882a593Smuzhiyun  notice appear in all copies and that both that copyright
8*4882a593Smuzhiyun  notice and this permission notice appear in supporting
9*4882a593Smuzhiyun  documentation, and that the name of Silicon Graphics not be
10*4882a593Smuzhiyun  used in advertising or publicity pertaining to distribution
11*4882a593Smuzhiyun  of the software without specific prior written permission.
12*4882a593Smuzhiyun  Silicon Graphics makes no representation about the suitability
13*4882a593Smuzhiyun  of this software for any purpose. It is provided "as is"
14*4882a593Smuzhiyun  without any express or implied warranty.
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun  SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17*4882a593Smuzhiyun  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18*4882a593Smuzhiyun  AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19*4882a593Smuzhiyun  GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20*4882a593Smuzhiyun  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21*4882a593Smuzhiyun  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22*4882a593Smuzhiyun  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23*4882a593Smuzhiyun  THE USE OR PERFORMANCE OF THIS SOFTWARE.
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun  ********************************************************/
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
28*4882a593Smuzhiyun #include <dix-config.h>
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <stdio.h>
32*4882a593Smuzhiyun #include <ctype.h>
33*4882a593Smuzhiyun #include <stdlib.h>
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define X_INCLUDE_STRING_H
36*4882a593Smuzhiyun #define XOS_USE_NO_LOCKING
37*4882a593Smuzhiyun #include <X11/Xos_r.h>
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #include <X11/Xproto.h>
40*4882a593Smuzhiyun #include <X11/X.h>
41*4882a593Smuzhiyun #include <X11/Xos.h>
42*4882a593Smuzhiyun #include <X11/Xfuncs.h>
43*4882a593Smuzhiyun #include <X11/Xatom.h>
44*4882a593Smuzhiyun #include <X11/keysym.h>
45*4882a593Smuzhiyun #include "misc.h"
46*4882a593Smuzhiyun #include "inputstr.h"
47*4882a593Smuzhiyun #include "dix.h"
48*4882a593Smuzhiyun #include "os.h"
49*4882a593Smuzhiyun #include "xkbstr.h"
50*4882a593Smuzhiyun #define XKBSRV_NEED_FILE_FUNCS
51*4882a593Smuzhiyun #include <xkbsrv.h>
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun /***====================================================================***/
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define DFLT_LINE_SIZE	128
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun typedef struct {
58*4882a593Smuzhiyun     int line_num;
59*4882a593Smuzhiyun     int sz_line;
60*4882a593Smuzhiyun     int num_line;
61*4882a593Smuzhiyun     char buf[DFLT_LINE_SIZE];
62*4882a593Smuzhiyun     char *line;
63*4882a593Smuzhiyun } InputLine;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun static void
InitInputLine(InputLine * line)66*4882a593Smuzhiyun InitInputLine(InputLine * line)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun     line->line_num = 1;
69*4882a593Smuzhiyun     line->num_line = 0;
70*4882a593Smuzhiyun     line->sz_line = DFLT_LINE_SIZE;
71*4882a593Smuzhiyun     line->line = line->buf;
72*4882a593Smuzhiyun     return;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun static void
FreeInputLine(InputLine * line)76*4882a593Smuzhiyun FreeInputLine(InputLine * line)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun     if (line->line != line->buf)
79*4882a593Smuzhiyun         free(line->line);
80*4882a593Smuzhiyun     line->line_num = 1;
81*4882a593Smuzhiyun     line->num_line = 0;
82*4882a593Smuzhiyun     line->sz_line = DFLT_LINE_SIZE;
83*4882a593Smuzhiyun     line->line = line->buf;
84*4882a593Smuzhiyun     return;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun static int
InputLineAddChar(InputLine * line,int ch)88*4882a593Smuzhiyun InputLineAddChar(InputLine * line, int ch)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun     if (line->num_line >= line->sz_line) {
91*4882a593Smuzhiyun         if (line->line == line->buf) {
92*4882a593Smuzhiyun             line->line = xallocarray(line->sz_line, 2);
93*4882a593Smuzhiyun             memcpy(line->line, line->buf, line->sz_line);
94*4882a593Smuzhiyun         }
95*4882a593Smuzhiyun         else {
96*4882a593Smuzhiyun             line->line = reallocarray(line->line, line->sz_line, 2);
97*4882a593Smuzhiyun         }
98*4882a593Smuzhiyun         line->sz_line *= 2;
99*4882a593Smuzhiyun     }
100*4882a593Smuzhiyun     line->line[line->num_line++] = ch;
101*4882a593Smuzhiyun     return ch;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun #define	ADD_CHAR(l,c)	((l)->num_line<(l)->sz_line?\
105*4882a593Smuzhiyun 				(int)((l)->line[(l)->num_line++]= (c)):\
106*4882a593Smuzhiyun 				InputLineAddChar(l,c))
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun static Bool
GetInputLine(FILE * file,InputLine * line,Bool checkbang)109*4882a593Smuzhiyun GetInputLine(FILE * file, InputLine * line, Bool checkbang)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun     int ch;
112*4882a593Smuzhiyun     Bool endOfFile, spacePending, slashPending, inComment;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun     endOfFile = FALSE;
115*4882a593Smuzhiyun     while ((!endOfFile) && (line->num_line == 0)) {
116*4882a593Smuzhiyun         spacePending = slashPending = inComment = FALSE;
117*4882a593Smuzhiyun         while (((ch = getc(file)) != '\n') && (ch != EOF)) {
118*4882a593Smuzhiyun             if (ch == '\\') {
119*4882a593Smuzhiyun                 if ((ch = getc(file)) == EOF)
120*4882a593Smuzhiyun                     break;
121*4882a593Smuzhiyun                 if (ch == '\n') {
122*4882a593Smuzhiyun                     inComment = FALSE;
123*4882a593Smuzhiyun                     ch = ' ';
124*4882a593Smuzhiyun                     line->line_num++;
125*4882a593Smuzhiyun                 }
126*4882a593Smuzhiyun             }
127*4882a593Smuzhiyun             if (inComment)
128*4882a593Smuzhiyun                 continue;
129*4882a593Smuzhiyun             if (ch == '/') {
130*4882a593Smuzhiyun                 if (slashPending) {
131*4882a593Smuzhiyun                     inComment = TRUE;
132*4882a593Smuzhiyun                     slashPending = FALSE;
133*4882a593Smuzhiyun                 }
134*4882a593Smuzhiyun                 else {
135*4882a593Smuzhiyun                     slashPending = TRUE;
136*4882a593Smuzhiyun                 }
137*4882a593Smuzhiyun                 continue;
138*4882a593Smuzhiyun             }
139*4882a593Smuzhiyun             else if (slashPending) {
140*4882a593Smuzhiyun                 if (spacePending) {
141*4882a593Smuzhiyun                     ADD_CHAR(line, ' ');
142*4882a593Smuzhiyun                     spacePending = FALSE;
143*4882a593Smuzhiyun                 }
144*4882a593Smuzhiyun                 ADD_CHAR(line, '/');
145*4882a593Smuzhiyun                 slashPending = FALSE;
146*4882a593Smuzhiyun             }
147*4882a593Smuzhiyun             if (isspace(ch)) {
148*4882a593Smuzhiyun                 while (isspace(ch) && (ch != '\n') && (ch != EOF)) {
149*4882a593Smuzhiyun                     ch = getc(file);
150*4882a593Smuzhiyun                 }
151*4882a593Smuzhiyun                 if (ch == EOF)
152*4882a593Smuzhiyun                     break;
153*4882a593Smuzhiyun                 if ((ch != '\n') && (line->num_line > 0))
154*4882a593Smuzhiyun                     spacePending = TRUE;
155*4882a593Smuzhiyun                 ungetc(ch, file);
156*4882a593Smuzhiyun             }
157*4882a593Smuzhiyun             else {
158*4882a593Smuzhiyun                 if (spacePending) {
159*4882a593Smuzhiyun                     ADD_CHAR(line, ' ');
160*4882a593Smuzhiyun                     spacePending = FALSE;
161*4882a593Smuzhiyun                 }
162*4882a593Smuzhiyun                 if (checkbang && ch == '!') {
163*4882a593Smuzhiyun                     if (line->num_line != 0) {
164*4882a593Smuzhiyun                         DebugF("The '!' legal only at start of line\n");
165*4882a593Smuzhiyun                         DebugF("Line containing '!' ignored\n");
166*4882a593Smuzhiyun                         line->num_line = 0;
167*4882a593Smuzhiyun                         inComment = 0;
168*4882a593Smuzhiyun                         break;
169*4882a593Smuzhiyun                     }
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun                 }
172*4882a593Smuzhiyun                 ADD_CHAR(line, ch);
173*4882a593Smuzhiyun             }
174*4882a593Smuzhiyun         }
175*4882a593Smuzhiyun         if (ch == EOF)
176*4882a593Smuzhiyun             endOfFile = TRUE;
177*4882a593Smuzhiyun /*	else line->num_line++;*/
178*4882a593Smuzhiyun     }
179*4882a593Smuzhiyun     if ((line->num_line == 0) && (endOfFile))
180*4882a593Smuzhiyun         return FALSE;
181*4882a593Smuzhiyun     ADD_CHAR(line, '\0');
182*4882a593Smuzhiyun     return TRUE;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun /***====================================================================***/
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun #define	MODEL		0
188*4882a593Smuzhiyun #define	LAYOUT		1
189*4882a593Smuzhiyun #define	VARIANT		2
190*4882a593Smuzhiyun #define	OPTION		3
191*4882a593Smuzhiyun #define	KEYCODES	4
192*4882a593Smuzhiyun #define SYMBOLS		5
193*4882a593Smuzhiyun #define	TYPES		6
194*4882a593Smuzhiyun #define	COMPAT		7
195*4882a593Smuzhiyun #define	GEOMETRY	8
196*4882a593Smuzhiyun #define	MAX_WORDS	9
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun #define	PART_MASK	0x000F
199*4882a593Smuzhiyun #define	COMPONENT_MASK	0x03F0
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun static const char *cname[MAX_WORDS] = {
202*4882a593Smuzhiyun     "model", "layout", "variant", "option",
203*4882a593Smuzhiyun     "keycodes", "symbols", "types", "compat", "geometry"
204*4882a593Smuzhiyun };
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun typedef struct _RemapSpec {
207*4882a593Smuzhiyun     int number;
208*4882a593Smuzhiyun     int num_remap;
209*4882a593Smuzhiyun     struct {
210*4882a593Smuzhiyun         int word;
211*4882a593Smuzhiyun         int index;
212*4882a593Smuzhiyun     } remap[MAX_WORDS];
213*4882a593Smuzhiyun } RemapSpec;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun typedef struct _FileSpec {
216*4882a593Smuzhiyun     char *name[MAX_WORDS];
217*4882a593Smuzhiyun     struct _FileSpec *pending;
218*4882a593Smuzhiyun } FileSpec;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun typedef struct {
221*4882a593Smuzhiyun     const char *model;
222*4882a593Smuzhiyun     const char *layout[XkbNumKbdGroups + 1];
223*4882a593Smuzhiyun     const char *variant[XkbNumKbdGroups + 1];
224*4882a593Smuzhiyun     const char *options;
225*4882a593Smuzhiyun } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun #define NDX_BUFF_SIZE	4
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun /***====================================================================***/
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun static char *
get_index(char * str,int * ndx)232*4882a593Smuzhiyun get_index(char *str, int *ndx)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun     char ndx_buf[NDX_BUFF_SIZE];
235*4882a593Smuzhiyun     char *end;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun     if (*str != '[') {
238*4882a593Smuzhiyun         *ndx = 0;
239*4882a593Smuzhiyun         return str;
240*4882a593Smuzhiyun     }
241*4882a593Smuzhiyun     str++;
242*4882a593Smuzhiyun     end = strchr(str, ']');
243*4882a593Smuzhiyun     if (end == NULL) {
244*4882a593Smuzhiyun         *ndx = -1;
245*4882a593Smuzhiyun         return str - 1;
246*4882a593Smuzhiyun     }
247*4882a593Smuzhiyun     if ((end - str) >= NDX_BUFF_SIZE) {
248*4882a593Smuzhiyun         *ndx = -1;
249*4882a593Smuzhiyun         return end + 1;
250*4882a593Smuzhiyun     }
251*4882a593Smuzhiyun     strlcpy(ndx_buf, str, 1 + end - str);
252*4882a593Smuzhiyun     *ndx = atoi(ndx_buf);
253*4882a593Smuzhiyun     return end + 1;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun static void
SetUpRemap(InputLine * line,RemapSpec * remap)257*4882a593Smuzhiyun SetUpRemap(InputLine * line, RemapSpec * remap)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun     char *tok, *str;
260*4882a593Smuzhiyun     unsigned present, l_ndx_present, v_ndx_present;
261*4882a593Smuzhiyun     register int i;
262*4882a593Smuzhiyun     int len, ndx;
263*4882a593Smuzhiyun     _Xstrtokparams strtok_buf;
264*4882a593Smuzhiyun     Bool found;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun     l_ndx_present = v_ndx_present = present = 0;
267*4882a593Smuzhiyun     str = &line->line[1];
268*4882a593Smuzhiyun     len = remap->number;
269*4882a593Smuzhiyun     memset((char *) remap, 0, sizeof(RemapSpec));
270*4882a593Smuzhiyun     remap->number = len;
271*4882a593Smuzhiyun     while ((tok = _XStrtok(str, " ", strtok_buf)) != NULL) {
272*4882a593Smuzhiyun         found = FALSE;
273*4882a593Smuzhiyun         str = NULL;
274*4882a593Smuzhiyun         if (strcmp(tok, "=") == 0)
275*4882a593Smuzhiyun             continue;
276*4882a593Smuzhiyun         for (i = 0; i < MAX_WORDS; i++) {
277*4882a593Smuzhiyun             len = strlen(cname[i]);
278*4882a593Smuzhiyun             if (strncmp(cname[i], tok, len) == 0) {
279*4882a593Smuzhiyun                 if (strlen(tok) > len) {
280*4882a593Smuzhiyun                     char *end = get_index(tok + len, &ndx);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun                     if ((i != LAYOUT && i != VARIANT) ||
283*4882a593Smuzhiyun                         *end != '\0' || ndx == -1)
284*4882a593Smuzhiyun                         break;
285*4882a593Smuzhiyun                     if (ndx < 1 || ndx > XkbNumKbdGroups) {
286*4882a593Smuzhiyun                         DebugF("Illegal %s index: %d\n", cname[i], ndx);
287*4882a593Smuzhiyun                         DebugF("Index must be in range 1..%d\n",
288*4882a593Smuzhiyun                                XkbNumKbdGroups);
289*4882a593Smuzhiyun                         break;
290*4882a593Smuzhiyun                     }
291*4882a593Smuzhiyun                 }
292*4882a593Smuzhiyun                 else {
293*4882a593Smuzhiyun                     ndx = 0;
294*4882a593Smuzhiyun                 }
295*4882a593Smuzhiyun                 found = TRUE;
296*4882a593Smuzhiyun                 if (present & (1 << i)) {
297*4882a593Smuzhiyun                     if ((i == LAYOUT && l_ndx_present & (1 << ndx)) ||
298*4882a593Smuzhiyun                         (i == VARIANT && v_ndx_present & (1 << ndx))) {
299*4882a593Smuzhiyun                         DebugF("Component \"%s\" listed twice\n", tok);
300*4882a593Smuzhiyun                         DebugF("Second definition ignored\n");
301*4882a593Smuzhiyun                         break;
302*4882a593Smuzhiyun                     }
303*4882a593Smuzhiyun                 }
304*4882a593Smuzhiyun                 present |= (1 << i);
305*4882a593Smuzhiyun                 if (i == LAYOUT)
306*4882a593Smuzhiyun                     l_ndx_present |= 1 << ndx;
307*4882a593Smuzhiyun                 if (i == VARIANT)
308*4882a593Smuzhiyun                     v_ndx_present |= 1 << ndx;
309*4882a593Smuzhiyun                 remap->remap[remap->num_remap].word = i;
310*4882a593Smuzhiyun                 remap->remap[remap->num_remap++].index = ndx;
311*4882a593Smuzhiyun                 break;
312*4882a593Smuzhiyun             }
313*4882a593Smuzhiyun         }
314*4882a593Smuzhiyun         if (!found) {
315*4882a593Smuzhiyun             fprintf(stderr, "Unknown component \"%s\" ignored\n", tok);
316*4882a593Smuzhiyun         }
317*4882a593Smuzhiyun     }
318*4882a593Smuzhiyun     if ((present & PART_MASK) == 0) {
319*4882a593Smuzhiyun         unsigned mask = PART_MASK;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun         ErrorF("Mapping needs at least one of ");
322*4882a593Smuzhiyun         for (i = 0; (i < MAX_WORDS); i++) {
323*4882a593Smuzhiyun             if ((1L << i) & mask) {
324*4882a593Smuzhiyun                 mask &= ~(1L << i);
325*4882a593Smuzhiyun                 if (mask)
326*4882a593Smuzhiyun                     DebugF("\"%s,\" ", cname[i]);
327*4882a593Smuzhiyun                 else
328*4882a593Smuzhiyun                     DebugF("or \"%s\"\n", cname[i]);
329*4882a593Smuzhiyun             }
330*4882a593Smuzhiyun         }
331*4882a593Smuzhiyun         DebugF("Illegal mapping ignored\n");
332*4882a593Smuzhiyun         remap->num_remap = 0;
333*4882a593Smuzhiyun         return;
334*4882a593Smuzhiyun     }
335*4882a593Smuzhiyun     if ((present & COMPONENT_MASK) == 0) {
336*4882a593Smuzhiyun         DebugF("Mapping needs at least one component\n");
337*4882a593Smuzhiyun         DebugF("Illegal mapping ignored\n");
338*4882a593Smuzhiyun         remap->num_remap = 0;
339*4882a593Smuzhiyun         return;
340*4882a593Smuzhiyun     }
341*4882a593Smuzhiyun     remap->number++;
342*4882a593Smuzhiyun     return;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun static Bool
MatchOneOf(const char * wanted,const char * vals_defined)346*4882a593Smuzhiyun MatchOneOf(const char *wanted, const char *vals_defined)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun     const char *str, *next;
349*4882a593Smuzhiyun     int want_len = strlen(wanted);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun     for (str = vals_defined, next = NULL; str != NULL; str = next) {
352*4882a593Smuzhiyun         int len;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun         next = strchr(str, ',');
355*4882a593Smuzhiyun         if (next) {
356*4882a593Smuzhiyun             len = next - str;
357*4882a593Smuzhiyun             next++;
358*4882a593Smuzhiyun         }
359*4882a593Smuzhiyun         else {
360*4882a593Smuzhiyun             len = strlen(str);
361*4882a593Smuzhiyun         }
362*4882a593Smuzhiyun         if ((len == want_len) && (strncmp(wanted, str, len) == 0))
363*4882a593Smuzhiyun             return TRUE;
364*4882a593Smuzhiyun     }
365*4882a593Smuzhiyun     return FALSE;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun /***====================================================================***/
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun static Bool
CheckLine(InputLine * line,RemapSpec * remap,XkbRF_RulePtr rule,XkbRF_GroupPtr group)371*4882a593Smuzhiyun CheckLine(InputLine * line,
372*4882a593Smuzhiyun           RemapSpec * remap, XkbRF_RulePtr rule, XkbRF_GroupPtr group)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun     char *str, *tok;
375*4882a593Smuzhiyun     register int nread, i;
376*4882a593Smuzhiyun     FileSpec tmp;
377*4882a593Smuzhiyun     _Xstrtokparams strtok_buf;
378*4882a593Smuzhiyun     Bool append = FALSE;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun     if (line->line[0] == '!') {
381*4882a593Smuzhiyun         if (line->line[1] == '$' ||
382*4882a593Smuzhiyun             (line->line[1] == ' ' && line->line[2] == '$')) {
383*4882a593Smuzhiyun             char *gname = strchr(line->line, '$');
384*4882a593Smuzhiyun             char *words = strchr(gname, ' ');
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun             if (!words)
387*4882a593Smuzhiyun                 return FALSE;
388*4882a593Smuzhiyun             *words++ = '\0';
389*4882a593Smuzhiyun             for (; *words; words++) {
390*4882a593Smuzhiyun                 if (*words != '=' && *words != ' ')
391*4882a593Smuzhiyun                     break;
392*4882a593Smuzhiyun             }
393*4882a593Smuzhiyun             if (*words == '\0')
394*4882a593Smuzhiyun                 return FALSE;
395*4882a593Smuzhiyun             group->name = Xstrdup(gname);
396*4882a593Smuzhiyun             group->words = Xstrdup(words);
397*4882a593Smuzhiyun             for (i = 1, words = group->words; *words; words++) {
398*4882a593Smuzhiyun                 if (*words == ' ') {
399*4882a593Smuzhiyun                     *words++ = '\0';
400*4882a593Smuzhiyun                     i++;
401*4882a593Smuzhiyun                 }
402*4882a593Smuzhiyun             }
403*4882a593Smuzhiyun             group->number = i;
404*4882a593Smuzhiyun             return TRUE;
405*4882a593Smuzhiyun         }
406*4882a593Smuzhiyun         else {
407*4882a593Smuzhiyun             SetUpRemap(line, remap);
408*4882a593Smuzhiyun             return FALSE;
409*4882a593Smuzhiyun         }
410*4882a593Smuzhiyun     }
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun     if (remap->num_remap == 0) {
413*4882a593Smuzhiyun         DebugF("Must have a mapping before first line of data\n");
414*4882a593Smuzhiyun         DebugF("Illegal line of data ignored\n");
415*4882a593Smuzhiyun         return FALSE;
416*4882a593Smuzhiyun     }
417*4882a593Smuzhiyun     memset((char *) &tmp, 0, sizeof(FileSpec));
418*4882a593Smuzhiyun     str = line->line;
419*4882a593Smuzhiyun     for (nread = 0; (tok = _XStrtok(str, " ", strtok_buf)) != NULL; nread++) {
420*4882a593Smuzhiyun         str = NULL;
421*4882a593Smuzhiyun         if (strcmp(tok, "=") == 0) {
422*4882a593Smuzhiyun             nread--;
423*4882a593Smuzhiyun             continue;
424*4882a593Smuzhiyun         }
425*4882a593Smuzhiyun         if (nread > remap->num_remap) {
426*4882a593Smuzhiyun             DebugF("Too many words on a line\n");
427*4882a593Smuzhiyun             DebugF("Extra word \"%s\" ignored\n", tok);
428*4882a593Smuzhiyun             continue;
429*4882a593Smuzhiyun         }
430*4882a593Smuzhiyun         tmp.name[remap->remap[nread].word] = tok;
431*4882a593Smuzhiyun         if (*tok == '+' || *tok == '|')
432*4882a593Smuzhiyun             append = TRUE;
433*4882a593Smuzhiyun     }
434*4882a593Smuzhiyun     if (nread < remap->num_remap) {
435*4882a593Smuzhiyun         DebugF("Too few words on a line: %s\n", line->line);
436*4882a593Smuzhiyun         DebugF("line ignored\n");
437*4882a593Smuzhiyun         return FALSE;
438*4882a593Smuzhiyun     }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun     rule->flags = 0;
441*4882a593Smuzhiyun     rule->number = remap->number;
442*4882a593Smuzhiyun     if (tmp.name[OPTION])
443*4882a593Smuzhiyun         rule->flags |= XkbRF_Option;
444*4882a593Smuzhiyun     else if (append)
445*4882a593Smuzhiyun         rule->flags |= XkbRF_Append;
446*4882a593Smuzhiyun     else
447*4882a593Smuzhiyun         rule->flags |= XkbRF_Normal;
448*4882a593Smuzhiyun     rule->model = Xstrdup(tmp.name[MODEL]);
449*4882a593Smuzhiyun     rule->layout = Xstrdup(tmp.name[LAYOUT]);
450*4882a593Smuzhiyun     rule->variant = Xstrdup(tmp.name[VARIANT]);
451*4882a593Smuzhiyun     rule->option = Xstrdup(tmp.name[OPTION]);
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun     rule->keycodes = Xstrdup(tmp.name[KEYCODES]);
454*4882a593Smuzhiyun     rule->symbols = Xstrdup(tmp.name[SYMBOLS]);
455*4882a593Smuzhiyun     rule->types = Xstrdup(tmp.name[TYPES]);
456*4882a593Smuzhiyun     rule->compat = Xstrdup(tmp.name[COMPAT]);
457*4882a593Smuzhiyun     rule->geometry = Xstrdup(tmp.name[GEOMETRY]);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun     rule->layout_num = rule->variant_num = 0;
460*4882a593Smuzhiyun     for (i = 0; i < nread; i++) {
461*4882a593Smuzhiyun         if (remap->remap[i].index) {
462*4882a593Smuzhiyun             if (remap->remap[i].word == LAYOUT)
463*4882a593Smuzhiyun                 rule->layout_num = remap->remap[i].index;
464*4882a593Smuzhiyun             if (remap->remap[i].word == VARIANT)
465*4882a593Smuzhiyun                 rule->variant_num = remap->remap[i].index;
466*4882a593Smuzhiyun         }
467*4882a593Smuzhiyun     }
468*4882a593Smuzhiyun     return TRUE;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun static char *
_Concat(char * str1,const char * str2)472*4882a593Smuzhiyun _Concat(char *str1, const char *str2)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun     int len;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun     if ((!str1) || (!str2))
477*4882a593Smuzhiyun         return str1;
478*4882a593Smuzhiyun     len = strlen(str1) + strlen(str2) + 1;
479*4882a593Smuzhiyun     str1 = realloc(str1, len * sizeof(char));
480*4882a593Smuzhiyun     if (str1)
481*4882a593Smuzhiyun         strcat(str1, str2);
482*4882a593Smuzhiyun     return str1;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun static void
squeeze_spaces(char * p1)486*4882a593Smuzhiyun squeeze_spaces(char *p1)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun     char *p2;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun     for (p2 = p1; *p2; p2++) {
491*4882a593Smuzhiyun         *p1 = *p2;
492*4882a593Smuzhiyun         if (*p1 != ' ')
493*4882a593Smuzhiyun             p1++;
494*4882a593Smuzhiyun     }
495*4882a593Smuzhiyun     *p1 = '\0';
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun static Bool
MakeMultiDefs(XkbRF_MultiDefsPtr mdefs,XkbRF_VarDefsPtr defs)499*4882a593Smuzhiyun MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun     char *options;
502*4882a593Smuzhiyun     memset((char *) mdefs, 0, sizeof(XkbRF_MultiDefsRec));
503*4882a593Smuzhiyun     mdefs->model = defs->model;
504*4882a593Smuzhiyun     options = Xstrdup(defs->options);
505*4882a593Smuzhiyun     if (options)
506*4882a593Smuzhiyun         squeeze_spaces(options);
507*4882a593Smuzhiyun     mdefs->options = options;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun     if (defs->layout) {
510*4882a593Smuzhiyun         if (!strchr(defs->layout, ',')) {
511*4882a593Smuzhiyun             mdefs->layout[0] = defs->layout;
512*4882a593Smuzhiyun         }
513*4882a593Smuzhiyun         else {
514*4882a593Smuzhiyun             char *p;
515*4882a593Smuzhiyun             char *layout;
516*4882a593Smuzhiyun             int i;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun             layout = Xstrdup(defs->layout);
519*4882a593Smuzhiyun             if (layout == NULL)
520*4882a593Smuzhiyun                 return FALSE;
521*4882a593Smuzhiyun             squeeze_spaces(layout);
522*4882a593Smuzhiyun             mdefs->layout[1] = layout;
523*4882a593Smuzhiyun             p = layout;
524*4882a593Smuzhiyun             for (i = 2; i <= XkbNumKbdGroups; i++) {
525*4882a593Smuzhiyun                 if ((p = strchr(p, ','))) {
526*4882a593Smuzhiyun                     *p++ = '\0';
527*4882a593Smuzhiyun                     mdefs->layout[i] = p;
528*4882a593Smuzhiyun                 }
529*4882a593Smuzhiyun                 else {
530*4882a593Smuzhiyun                     break;
531*4882a593Smuzhiyun                 }
532*4882a593Smuzhiyun             }
533*4882a593Smuzhiyun             if (p && (p = strchr(p, ',')))
534*4882a593Smuzhiyun                 *p = '\0';
535*4882a593Smuzhiyun         }
536*4882a593Smuzhiyun     }
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun     if (defs->variant) {
539*4882a593Smuzhiyun         if (!strchr(defs->variant, ',')) {
540*4882a593Smuzhiyun             mdefs->variant[0] = defs->variant;
541*4882a593Smuzhiyun         }
542*4882a593Smuzhiyun         else {
543*4882a593Smuzhiyun             char *p;
544*4882a593Smuzhiyun             char *variant;
545*4882a593Smuzhiyun             int i;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun             variant = Xstrdup(defs->variant);
548*4882a593Smuzhiyun             if (variant == NULL)
549*4882a593Smuzhiyun                 return FALSE;
550*4882a593Smuzhiyun             squeeze_spaces(variant);
551*4882a593Smuzhiyun             mdefs->variant[1] = variant;
552*4882a593Smuzhiyun             p = variant;
553*4882a593Smuzhiyun             for (i = 2; i <= XkbNumKbdGroups; i++) {
554*4882a593Smuzhiyun                 if ((p = strchr(p, ','))) {
555*4882a593Smuzhiyun                     *p++ = '\0';
556*4882a593Smuzhiyun                     mdefs->variant[i] = p;
557*4882a593Smuzhiyun                 }
558*4882a593Smuzhiyun                 else {
559*4882a593Smuzhiyun                     break;
560*4882a593Smuzhiyun                 }
561*4882a593Smuzhiyun             }
562*4882a593Smuzhiyun             if (p && (p = strchr(p, ',')))
563*4882a593Smuzhiyun                 *p = '\0';
564*4882a593Smuzhiyun         }
565*4882a593Smuzhiyun     }
566*4882a593Smuzhiyun     return TRUE;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun static void
FreeMultiDefs(XkbRF_MultiDefsPtr defs)570*4882a593Smuzhiyun FreeMultiDefs(XkbRF_MultiDefsPtr defs)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun     free((void *) defs->options);
573*4882a593Smuzhiyun     free((void *) defs->layout[1]);
574*4882a593Smuzhiyun     free((void *) defs->variant[1]);
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun static void
Apply(const char * src,char ** dst)578*4882a593Smuzhiyun Apply(const char *src, char **dst)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun     if (src) {
581*4882a593Smuzhiyun         if (*src == '+' || *src == '|') {
582*4882a593Smuzhiyun             *dst = _Concat(*dst, src);
583*4882a593Smuzhiyun         }
584*4882a593Smuzhiyun         else {
585*4882a593Smuzhiyun             if (*dst == NULL)
586*4882a593Smuzhiyun                 *dst = Xstrdup(src);
587*4882a593Smuzhiyun         }
588*4882a593Smuzhiyun     }
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun static void
XkbRF_ApplyRule(XkbRF_RulePtr rule,XkbComponentNamesPtr names)592*4882a593Smuzhiyun XkbRF_ApplyRule(XkbRF_RulePtr rule, XkbComponentNamesPtr names)
593*4882a593Smuzhiyun {
594*4882a593Smuzhiyun     rule->flags &= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun     Apply(rule->keycodes, &names->keycodes);
597*4882a593Smuzhiyun     Apply(rule->symbols, &names->symbols);
598*4882a593Smuzhiyun     Apply(rule->types, &names->types);
599*4882a593Smuzhiyun     Apply(rule->compat, &names->compat);
600*4882a593Smuzhiyun     Apply(rule->geometry, &names->geometry);
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun static Bool
CheckGroup(XkbRF_RulesPtr rules,const char * group_name,const char * name)604*4882a593Smuzhiyun CheckGroup(XkbRF_RulesPtr rules, const char *group_name, const char *name)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun     int i;
607*4882a593Smuzhiyun     char *p;
608*4882a593Smuzhiyun     XkbRF_GroupPtr group;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun     for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
611*4882a593Smuzhiyun         if (!strcmp(group->name, group_name)) {
612*4882a593Smuzhiyun             break;
613*4882a593Smuzhiyun         }
614*4882a593Smuzhiyun     }
615*4882a593Smuzhiyun     if (i == rules->num_groups)
616*4882a593Smuzhiyun         return FALSE;
617*4882a593Smuzhiyun     for (i = 0, p = group->words; i < group->number; i++, p += strlen(p) + 1) {
618*4882a593Smuzhiyun         if (!strcmp(p, name)) {
619*4882a593Smuzhiyun             return TRUE;
620*4882a593Smuzhiyun         }
621*4882a593Smuzhiyun     }
622*4882a593Smuzhiyun     return FALSE;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun static int
XkbRF_CheckApplyRule(XkbRF_RulePtr rule,XkbRF_MultiDefsPtr mdefs,XkbComponentNamesPtr names,XkbRF_RulesPtr rules)626*4882a593Smuzhiyun XkbRF_CheckApplyRule(XkbRF_RulePtr rule,
627*4882a593Smuzhiyun                      XkbRF_MultiDefsPtr mdefs,
628*4882a593Smuzhiyun                      XkbComponentNamesPtr names, XkbRF_RulesPtr rules)
629*4882a593Smuzhiyun {
630*4882a593Smuzhiyun     Bool pending = FALSE;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun     if (rule->model != NULL) {
633*4882a593Smuzhiyun         if (mdefs->model == NULL)
634*4882a593Smuzhiyun             return 0;
635*4882a593Smuzhiyun         if (strcmp(rule->model, "*") == 0) {
636*4882a593Smuzhiyun             pending = TRUE;
637*4882a593Smuzhiyun         }
638*4882a593Smuzhiyun         else {
639*4882a593Smuzhiyun             if (rule->model[0] == '$') {
640*4882a593Smuzhiyun                 if (!CheckGroup(rules, rule->model, mdefs->model))
641*4882a593Smuzhiyun                     return 0;
642*4882a593Smuzhiyun             }
643*4882a593Smuzhiyun             else {
644*4882a593Smuzhiyun                 if (strcmp(rule->model, mdefs->model) != 0)
645*4882a593Smuzhiyun                     return 0;
646*4882a593Smuzhiyun             }
647*4882a593Smuzhiyun         }
648*4882a593Smuzhiyun     }
649*4882a593Smuzhiyun     if (rule->option != NULL) {
650*4882a593Smuzhiyun         if (mdefs->options == NULL)
651*4882a593Smuzhiyun             return 0;
652*4882a593Smuzhiyun         if ((!MatchOneOf(rule->option, mdefs->options)))
653*4882a593Smuzhiyun             return 0;
654*4882a593Smuzhiyun     }
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun     if (rule->layout != NULL) {
657*4882a593Smuzhiyun         if (mdefs->layout[rule->layout_num] == NULL ||
658*4882a593Smuzhiyun             *mdefs->layout[rule->layout_num] == '\0')
659*4882a593Smuzhiyun             return 0;
660*4882a593Smuzhiyun         if (strcmp(rule->layout, "*") == 0) {
661*4882a593Smuzhiyun             pending = TRUE;
662*4882a593Smuzhiyun         }
663*4882a593Smuzhiyun         else {
664*4882a593Smuzhiyun             if (rule->layout[0] == '$') {
665*4882a593Smuzhiyun                 if (!CheckGroup(rules, rule->layout,
666*4882a593Smuzhiyun                                 mdefs->layout[rule->layout_num]))
667*4882a593Smuzhiyun                     return 0;
668*4882a593Smuzhiyun             }
669*4882a593Smuzhiyun             else {
670*4882a593Smuzhiyun                 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
671*4882a593Smuzhiyun                     return 0;
672*4882a593Smuzhiyun             }
673*4882a593Smuzhiyun         }
674*4882a593Smuzhiyun     }
675*4882a593Smuzhiyun     if (rule->variant != NULL) {
676*4882a593Smuzhiyun         if (mdefs->variant[rule->variant_num] == NULL ||
677*4882a593Smuzhiyun             *mdefs->variant[rule->variant_num] == '\0')
678*4882a593Smuzhiyun             return 0;
679*4882a593Smuzhiyun         if (strcmp(rule->variant, "*") == 0) {
680*4882a593Smuzhiyun             pending = TRUE;
681*4882a593Smuzhiyun         }
682*4882a593Smuzhiyun         else {
683*4882a593Smuzhiyun             if (rule->variant[0] == '$') {
684*4882a593Smuzhiyun                 if (!CheckGroup(rules, rule->variant,
685*4882a593Smuzhiyun                                 mdefs->variant[rule->variant_num]))
686*4882a593Smuzhiyun                     return 0;
687*4882a593Smuzhiyun             }
688*4882a593Smuzhiyun             else {
689*4882a593Smuzhiyun                 if (strcmp(rule->variant,
690*4882a593Smuzhiyun                            mdefs->variant[rule->variant_num]) != 0)
691*4882a593Smuzhiyun                     return 0;
692*4882a593Smuzhiyun             }
693*4882a593Smuzhiyun         }
694*4882a593Smuzhiyun     }
695*4882a593Smuzhiyun     if (pending) {
696*4882a593Smuzhiyun         rule->flags |= XkbRF_PendingMatch;
697*4882a593Smuzhiyun         return rule->number;
698*4882a593Smuzhiyun     }
699*4882a593Smuzhiyun     /* exact match, apply it now */
700*4882a593Smuzhiyun     XkbRF_ApplyRule(rule, names);
701*4882a593Smuzhiyun     return rule->number;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun static void
XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)705*4882a593Smuzhiyun XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun     register int i;
708*4882a593Smuzhiyun     XkbRF_RulePtr rule;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun     for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) {
711*4882a593Smuzhiyun         rule->flags &= ~XkbRF_PendingMatch;
712*4882a593Smuzhiyun     }
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun static void
XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names)716*4882a593Smuzhiyun XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules, XkbComponentNamesPtr names)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun     int i;
719*4882a593Smuzhiyun     XkbRF_RulePtr rule;
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun     for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
722*4882a593Smuzhiyun         if ((rule->flags & XkbRF_PendingMatch) == 0)
723*4882a593Smuzhiyun             continue;
724*4882a593Smuzhiyun         XkbRF_ApplyRule(rule, names);
725*4882a593Smuzhiyun     }
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun static void
XkbRF_CheckApplyRules(XkbRF_RulesPtr rules,XkbRF_MultiDefsPtr mdefs,XkbComponentNamesPtr names,int flags)729*4882a593Smuzhiyun XkbRF_CheckApplyRules(XkbRF_RulesPtr rules,
730*4882a593Smuzhiyun                       XkbRF_MultiDefsPtr mdefs,
731*4882a593Smuzhiyun                       XkbComponentNamesPtr names, int flags)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun     int i;
734*4882a593Smuzhiyun     XkbRF_RulePtr rule;
735*4882a593Smuzhiyun     int skip;
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun     for (rule = rules->rules, i = 0; i < rules->num_rules; rule++, i++) {
738*4882a593Smuzhiyun         if ((rule->flags & flags) != flags)
739*4882a593Smuzhiyun             continue;
740*4882a593Smuzhiyun         skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
741*4882a593Smuzhiyun         if (skip && !(flags & XkbRF_Option)) {
742*4882a593Smuzhiyun             for (; (i < rules->num_rules) && (rule->number == skip);
743*4882a593Smuzhiyun                  rule++, i++);
744*4882a593Smuzhiyun             rule--;
745*4882a593Smuzhiyun             i--;
746*4882a593Smuzhiyun         }
747*4882a593Smuzhiyun     }
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun /***====================================================================***/
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun static char *
XkbRF_SubstituteVars(char * name,XkbRF_MultiDefsPtr mdefs)753*4882a593Smuzhiyun XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun     char *str, *outstr, *orig, *var;
756*4882a593Smuzhiyun     int len, ndx;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun     orig = name;
759*4882a593Smuzhiyun     str = index(name, '%');
760*4882a593Smuzhiyun     if (str == NULL)
761*4882a593Smuzhiyun         return name;
762*4882a593Smuzhiyun     len = strlen(name);
763*4882a593Smuzhiyun     while (str != NULL) {
764*4882a593Smuzhiyun         char pfx = str[1];
765*4882a593Smuzhiyun         int extra_len = 0;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun         if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) {
768*4882a593Smuzhiyun             extra_len = 1;
769*4882a593Smuzhiyun             str++;
770*4882a593Smuzhiyun         }
771*4882a593Smuzhiyun         else if (pfx == '(') {
772*4882a593Smuzhiyun             extra_len = 2;
773*4882a593Smuzhiyun             str++;
774*4882a593Smuzhiyun         }
775*4882a593Smuzhiyun         var = str + 1;
776*4882a593Smuzhiyun         str = get_index(var + 1, &ndx);
777*4882a593Smuzhiyun         if (ndx == -1) {
778*4882a593Smuzhiyun             str = index(str, '%');
779*4882a593Smuzhiyun             continue;
780*4882a593Smuzhiyun         }
781*4882a593Smuzhiyun         if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
782*4882a593Smuzhiyun             len += strlen(mdefs->layout[ndx]) + extra_len;
783*4882a593Smuzhiyun         else if ((*var == 'm') && mdefs->model)
784*4882a593Smuzhiyun             len += strlen(mdefs->model) + extra_len;
785*4882a593Smuzhiyun         else if ((*var == 'v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
786*4882a593Smuzhiyun             len += strlen(mdefs->variant[ndx]) + extra_len;
787*4882a593Smuzhiyun         if ((pfx == '(') && (*str == ')')) {
788*4882a593Smuzhiyun             str++;
789*4882a593Smuzhiyun         }
790*4882a593Smuzhiyun         str = index(&str[0], '%');
791*4882a593Smuzhiyun     }
792*4882a593Smuzhiyun     name = malloc(len + 1);
793*4882a593Smuzhiyun     str = orig;
794*4882a593Smuzhiyun     outstr = name;
795*4882a593Smuzhiyun     while (*str != '\0') {
796*4882a593Smuzhiyun         if (str[0] == '%') {
797*4882a593Smuzhiyun             char pfx, sfx;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun             str++;
800*4882a593Smuzhiyun             pfx = str[0];
801*4882a593Smuzhiyun             sfx = '\0';
802*4882a593Smuzhiyun             if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) {
803*4882a593Smuzhiyun                 str++;
804*4882a593Smuzhiyun             }
805*4882a593Smuzhiyun             else if (pfx == '(') {
806*4882a593Smuzhiyun                 sfx = ')';
807*4882a593Smuzhiyun                 str++;
808*4882a593Smuzhiyun             }
809*4882a593Smuzhiyun             else
810*4882a593Smuzhiyun                 pfx = '\0';
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun             var = str;
813*4882a593Smuzhiyun             str = get_index(var + 1, &ndx);
814*4882a593Smuzhiyun             if (ndx == -1) {
815*4882a593Smuzhiyun                 continue;
816*4882a593Smuzhiyun             }
817*4882a593Smuzhiyun             if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
818*4882a593Smuzhiyun                 if (pfx)
819*4882a593Smuzhiyun                     *outstr++ = pfx;
820*4882a593Smuzhiyun                 strcpy(outstr, mdefs->layout[ndx]);
821*4882a593Smuzhiyun                 outstr += strlen(mdefs->layout[ndx]);
822*4882a593Smuzhiyun                 if (sfx)
823*4882a593Smuzhiyun                     *outstr++ = sfx;
824*4882a593Smuzhiyun             }
825*4882a593Smuzhiyun             else if ((*var == 'm') && (mdefs->model)) {
826*4882a593Smuzhiyun                 if (pfx)
827*4882a593Smuzhiyun                     *outstr++ = pfx;
828*4882a593Smuzhiyun                 strcpy(outstr, mdefs->model);
829*4882a593Smuzhiyun                 outstr += strlen(mdefs->model);
830*4882a593Smuzhiyun                 if (sfx)
831*4882a593Smuzhiyun                     *outstr++ = sfx;
832*4882a593Smuzhiyun             }
833*4882a593Smuzhiyun             else if ((*var == 'v') && mdefs->variant[ndx] &&
834*4882a593Smuzhiyun                      *mdefs->variant[ndx]) {
835*4882a593Smuzhiyun                 if (pfx)
836*4882a593Smuzhiyun                     *outstr++ = pfx;
837*4882a593Smuzhiyun                 strcpy(outstr, mdefs->variant[ndx]);
838*4882a593Smuzhiyun                 outstr += strlen(mdefs->variant[ndx]);
839*4882a593Smuzhiyun                 if (sfx)
840*4882a593Smuzhiyun                     *outstr++ = sfx;
841*4882a593Smuzhiyun             }
842*4882a593Smuzhiyun             if ((pfx == '(') && (*str == ')'))
843*4882a593Smuzhiyun                 str++;
844*4882a593Smuzhiyun         }
845*4882a593Smuzhiyun         else {
846*4882a593Smuzhiyun             *outstr++ = *str++;
847*4882a593Smuzhiyun         }
848*4882a593Smuzhiyun     }
849*4882a593Smuzhiyun     *outstr++ = '\0';
850*4882a593Smuzhiyun     if (orig != name)
851*4882a593Smuzhiyun         free(orig);
852*4882a593Smuzhiyun     return name;
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun /***====================================================================***/
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun Bool
XkbRF_GetComponents(XkbRF_RulesPtr rules,XkbRF_VarDefsPtr defs,XkbComponentNamesPtr names)858*4882a593Smuzhiyun XkbRF_GetComponents(XkbRF_RulesPtr rules,
859*4882a593Smuzhiyun                     XkbRF_VarDefsPtr defs, XkbComponentNamesPtr names)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun     XkbRF_MultiDefsRec mdefs;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun     MakeMultiDefs(&mdefs, defs);
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun     memset((char *) names, 0, sizeof(XkbComponentNamesRec));
866*4882a593Smuzhiyun     XkbRF_ClearPartialMatches(rules);
867*4882a593Smuzhiyun     XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
868*4882a593Smuzhiyun     XkbRF_ApplyPartialMatches(rules, names);
869*4882a593Smuzhiyun     XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
870*4882a593Smuzhiyun     XkbRF_ApplyPartialMatches(rules, names);
871*4882a593Smuzhiyun     XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
872*4882a593Smuzhiyun     XkbRF_ApplyPartialMatches(rules, names);
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun     if (names->keycodes)
875*4882a593Smuzhiyun         names->keycodes = XkbRF_SubstituteVars(names->keycodes, &mdefs);
876*4882a593Smuzhiyun     if (names->symbols)
877*4882a593Smuzhiyun         names->symbols = XkbRF_SubstituteVars(names->symbols, &mdefs);
878*4882a593Smuzhiyun     if (names->types)
879*4882a593Smuzhiyun         names->types = XkbRF_SubstituteVars(names->types, &mdefs);
880*4882a593Smuzhiyun     if (names->compat)
881*4882a593Smuzhiyun         names->compat = XkbRF_SubstituteVars(names->compat, &mdefs);
882*4882a593Smuzhiyun     if (names->geometry)
883*4882a593Smuzhiyun         names->geometry = XkbRF_SubstituteVars(names->geometry, &mdefs);
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun     FreeMultiDefs(&mdefs);
886*4882a593Smuzhiyun     return (names->keycodes && names->symbols && names->types &&
887*4882a593Smuzhiyun             names->compat && names->geometry);
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun static XkbRF_RulePtr
XkbRF_AddRule(XkbRF_RulesPtr rules)891*4882a593Smuzhiyun XkbRF_AddRule(XkbRF_RulesPtr rules)
892*4882a593Smuzhiyun {
893*4882a593Smuzhiyun     if (rules->sz_rules < 1) {
894*4882a593Smuzhiyun         rules->sz_rules = 16;
895*4882a593Smuzhiyun         rules->num_rules = 0;
896*4882a593Smuzhiyun         rules->rules = calloc(rules->sz_rules, sizeof(XkbRF_RuleRec));
897*4882a593Smuzhiyun     }
898*4882a593Smuzhiyun     else if (rules->num_rules >= rules->sz_rules) {
899*4882a593Smuzhiyun         rules->sz_rules *= 2;
900*4882a593Smuzhiyun         rules->rules = reallocarray(rules->rules,
901*4882a593Smuzhiyun                                     rules->sz_rules, sizeof(XkbRF_RuleRec));
902*4882a593Smuzhiyun     }
903*4882a593Smuzhiyun     if (!rules->rules) {
904*4882a593Smuzhiyun         rules->sz_rules = rules->num_rules = 0;
905*4882a593Smuzhiyun         DebugF("Allocation failure in XkbRF_AddRule\n");
906*4882a593Smuzhiyun         return NULL;
907*4882a593Smuzhiyun     }
908*4882a593Smuzhiyun     memset((char *) &rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
909*4882a593Smuzhiyun     return &rules->rules[rules->num_rules++];
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun static XkbRF_GroupPtr
XkbRF_AddGroup(XkbRF_RulesPtr rules)913*4882a593Smuzhiyun XkbRF_AddGroup(XkbRF_RulesPtr rules)
914*4882a593Smuzhiyun {
915*4882a593Smuzhiyun     if (rules->sz_groups < 1) {
916*4882a593Smuzhiyun         rules->sz_groups = 16;
917*4882a593Smuzhiyun         rules->num_groups = 0;
918*4882a593Smuzhiyun         rules->groups = calloc(rules->sz_groups, sizeof(XkbRF_GroupRec));
919*4882a593Smuzhiyun     }
920*4882a593Smuzhiyun     else if (rules->num_groups >= rules->sz_groups) {
921*4882a593Smuzhiyun         rules->sz_groups *= 2;
922*4882a593Smuzhiyun         rules->groups = reallocarray(rules->groups,
923*4882a593Smuzhiyun                                      rules->sz_groups, sizeof(XkbRF_GroupRec));
924*4882a593Smuzhiyun     }
925*4882a593Smuzhiyun     if (!rules->groups) {
926*4882a593Smuzhiyun         rules->sz_groups = rules->num_groups = 0;
927*4882a593Smuzhiyun         return NULL;
928*4882a593Smuzhiyun     }
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun     memset((char *) &rules->groups[rules->num_groups], 0,
931*4882a593Smuzhiyun            sizeof(XkbRF_GroupRec));
932*4882a593Smuzhiyun     return &rules->groups[rules->num_groups++];
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun Bool
XkbRF_LoadRules(FILE * file,XkbRF_RulesPtr rules)936*4882a593Smuzhiyun XkbRF_LoadRules(FILE * file, XkbRF_RulesPtr rules)
937*4882a593Smuzhiyun {
938*4882a593Smuzhiyun     InputLine line;
939*4882a593Smuzhiyun     RemapSpec remap;
940*4882a593Smuzhiyun     XkbRF_RuleRec trule, *rule;
941*4882a593Smuzhiyun     XkbRF_GroupRec tgroup, *group;
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun     if (!(rules && file))
944*4882a593Smuzhiyun         return FALSE;
945*4882a593Smuzhiyun     memset((char *) &remap, 0, sizeof(RemapSpec));
946*4882a593Smuzhiyun     memset((char *) &tgroup, 0, sizeof(XkbRF_GroupRec));
947*4882a593Smuzhiyun     InitInputLine(&line);
948*4882a593Smuzhiyun     while (GetInputLine(file, &line, TRUE)) {
949*4882a593Smuzhiyun         if (CheckLine(&line, &remap, &trule, &tgroup)) {
950*4882a593Smuzhiyun             if (tgroup.number) {
951*4882a593Smuzhiyun                 if ((group = XkbRF_AddGroup(rules)) != NULL) {
952*4882a593Smuzhiyun                     *group = tgroup;
953*4882a593Smuzhiyun                     memset((char *) &tgroup, 0, sizeof(XkbRF_GroupRec));
954*4882a593Smuzhiyun                 }
955*4882a593Smuzhiyun             }
956*4882a593Smuzhiyun             else {
957*4882a593Smuzhiyun                 if ((rule = XkbRF_AddRule(rules)) != NULL) {
958*4882a593Smuzhiyun                     *rule = trule;
959*4882a593Smuzhiyun                     memset((char *) &trule, 0, sizeof(XkbRF_RuleRec));
960*4882a593Smuzhiyun                 }
961*4882a593Smuzhiyun             }
962*4882a593Smuzhiyun         }
963*4882a593Smuzhiyun         line.num_line = 0;
964*4882a593Smuzhiyun     }
965*4882a593Smuzhiyun     FreeInputLine(&line);
966*4882a593Smuzhiyun     return TRUE;
967*4882a593Smuzhiyun }
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun Bool
XkbRF_LoadRulesByName(char * base,char * locale,XkbRF_RulesPtr rules)970*4882a593Smuzhiyun XkbRF_LoadRulesByName(char *base, char *locale, XkbRF_RulesPtr rules)
971*4882a593Smuzhiyun {
972*4882a593Smuzhiyun     FILE *file;
973*4882a593Smuzhiyun     char buf[PATH_MAX];
974*4882a593Smuzhiyun     Bool ok;
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun     if ((!base) || (!rules))
977*4882a593Smuzhiyun         return FALSE;
978*4882a593Smuzhiyun     if (locale) {
979*4882a593Smuzhiyun         if (snprintf(buf, PATH_MAX, "%s-%s", base, locale) >= PATH_MAX)
980*4882a593Smuzhiyun             return FALSE;
981*4882a593Smuzhiyun     }
982*4882a593Smuzhiyun     else {
983*4882a593Smuzhiyun         if (strlen(base) + 1 > PATH_MAX)
984*4882a593Smuzhiyun             return FALSE;
985*4882a593Smuzhiyun         strcpy(buf, base);
986*4882a593Smuzhiyun     }
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun     file = fopen(buf, "r");
989*4882a593Smuzhiyun     if ((!file) && (locale)) {  /* fallback if locale was specified */
990*4882a593Smuzhiyun         strcpy(buf, base);
991*4882a593Smuzhiyun         file = fopen(buf, "r");
992*4882a593Smuzhiyun     }
993*4882a593Smuzhiyun     if (!file)
994*4882a593Smuzhiyun         return FALSE;
995*4882a593Smuzhiyun     ok = XkbRF_LoadRules(file, rules);
996*4882a593Smuzhiyun     fclose(file);
997*4882a593Smuzhiyun     return ok;
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun /***====================================================================***/
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun XkbRF_RulesPtr
XkbRF_Create(void)1003*4882a593Smuzhiyun XkbRF_Create(void)
1004*4882a593Smuzhiyun {
1005*4882a593Smuzhiyun     return calloc(1, sizeof(XkbRF_RulesRec));
1006*4882a593Smuzhiyun }
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun /***====================================================================***/
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun void
XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules)1011*4882a593Smuzhiyun XkbRF_Free(XkbRF_RulesPtr rules, Bool freeRules)
1012*4882a593Smuzhiyun {
1013*4882a593Smuzhiyun     int i;
1014*4882a593Smuzhiyun     XkbRF_RulePtr rule;
1015*4882a593Smuzhiyun     XkbRF_GroupPtr group;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun     if (!rules)
1018*4882a593Smuzhiyun         return;
1019*4882a593Smuzhiyun     if (rules->rules) {
1020*4882a593Smuzhiyun         for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) {
1021*4882a593Smuzhiyun             free((void *) rule->model);
1022*4882a593Smuzhiyun             free((void *) rule->layout);
1023*4882a593Smuzhiyun             free((void *) rule->variant);
1024*4882a593Smuzhiyun             free((void *) rule->option);
1025*4882a593Smuzhiyun             free((void *) rule->keycodes);
1026*4882a593Smuzhiyun             free((void *) rule->symbols);
1027*4882a593Smuzhiyun             free((void *) rule->types);
1028*4882a593Smuzhiyun             free((void *) rule->compat);
1029*4882a593Smuzhiyun             free((void *) rule->geometry);
1030*4882a593Smuzhiyun             memset((char *) rule, 0, sizeof(XkbRF_RuleRec));
1031*4882a593Smuzhiyun         }
1032*4882a593Smuzhiyun         free(rules->rules);
1033*4882a593Smuzhiyun         rules->num_rules = rules->sz_rules = 0;
1034*4882a593Smuzhiyun         rules->rules = NULL;
1035*4882a593Smuzhiyun     }
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun     if (rules->groups) {
1038*4882a593Smuzhiyun         for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
1039*4882a593Smuzhiyun             free((void *) group->name);
1040*4882a593Smuzhiyun             free(group->words);
1041*4882a593Smuzhiyun         }
1042*4882a593Smuzhiyun         free(rules->groups);
1043*4882a593Smuzhiyun         rules->num_groups = 0;
1044*4882a593Smuzhiyun         rules->groups = NULL;
1045*4882a593Smuzhiyun     }
1046*4882a593Smuzhiyun     if (freeRules)
1047*4882a593Smuzhiyun         free(rules);
1048*4882a593Smuzhiyun     return;
1049*4882a593Smuzhiyun }
1050