1 /************************************************************
2 Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc.
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 ********************************************************/
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
35 #define X_INCLUDE_STRING_H
36 #define XOS_USE_NO_LOCKING
37 #include <X11/Xos_r.h>
39 #include <X11/Xproto.h>
42 #include <X11/Xfuncs.h>
43 #include <X11/Xatom.h>
44 #include <X11/keysym.h>
50 #define XKBSRV_NEED_FILE_FUNCS
53 /***====================================================================***/
55 #define DFLT_LINE_SIZE 128
61 char buf
[DFLT_LINE_SIZE
];
66 InitInputLine(InputLine
* line
)
70 line
->sz_line
= DFLT_LINE_SIZE
;
71 line
->line
= line
->buf
;
76 FreeInputLine(InputLine
* line
)
78 if (line
->line
!= line
->buf
)
82 line
->sz_line
= DFLT_LINE_SIZE
;
83 line
->line
= line
->buf
;
88 InputLineAddChar(InputLine
* line
, int ch
)
90 if (line
->num_line
>= line
->sz_line
) {
91 if (line
->line
== line
->buf
) {
92 line
->line
= malloc(line
->sz_line
* 2);
93 memcpy(line
->line
, line
->buf
, line
->sz_line
);
96 line
->line
= realloc((char *) line
->line
, line
->sz_line
* 2);
100 line
->line
[line
->num_line
++] = ch
;
104 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
105 (int)((l)->line[(l)->num_line++]= (c)):\
106 InputLineAddChar(l,c))
109 GetInputLine(FILE * file
, InputLine
* line
, Bool checkbang
)
112 Bool endOfFile
, spacePending
, slashPending
, inComment
;
115 while ((!endOfFile
) && (line
->num_line
== 0)) {
116 spacePending
= slashPending
= inComment
= FALSE
;
117 while (((ch
= getc(file
)) != '\n') && (ch
!= EOF
)) {
119 if ((ch
= getc(file
)) == EOF
)
132 slashPending
= FALSE
;
139 else if (slashPending
) {
142 spacePending
= FALSE
;
145 slashPending
= FALSE
;
148 while (isspace(ch
) && (ch
!= '\n') && (ch
!= EOF
)) {
153 if ((ch
!= '\n') && (line
->num_line
> 0))
160 spacePending
= FALSE
;
162 if (checkbang
&& ch
== '!') {
163 if (line
->num_line
!= 0) {
164 DebugF("The '!' legal only at start of line\n");
165 DebugF("Line containing '!' ignored\n");
177 /* else line->num_line++;*/
179 if ((line
->num_line
== 0) && (endOfFile
))
181 ADD_CHAR(line
, '\0');
185 /***====================================================================***/
198 #define PART_MASK 0x000F
199 #define COMPONENT_MASK 0x03F0
201 static const char *cname
[MAX_WORDS
] = {
202 "model", "layout", "variant", "option",
203 "keycodes", "symbols", "types", "compat", "geometry"
206 typedef struct _RemapSpec
{
215 typedef struct _FileSpec
{
216 char *name
[MAX_WORDS
];
217 struct _FileSpec
*pending
;
222 char *layout
[XkbNumKbdGroups
+ 1];
223 char *variant
[XkbNumKbdGroups
+ 1];
225 } XkbRF_MultiDefsRec
, *XkbRF_MultiDefsPtr
;
227 #define NDX_BUFF_SIZE 4
229 /***====================================================================***/
232 get_index(char *str
, int *ndx
)
234 char ndx_buf
[NDX_BUFF_SIZE
];
242 end
= strchr(str
, ']');
247 if ((end
- str
) >= NDX_BUFF_SIZE
) {
251 strlcpy(ndx_buf
, str
, 1 + end
- str
);
252 *ndx
= atoi(ndx_buf
);
257 SetUpRemap(InputLine
* line
, RemapSpec
* remap
)
260 unsigned present
, l_ndx_present
, v_ndx_present
;
263 _Xstrtokparams strtok_buf
;
266 l_ndx_present
= v_ndx_present
= present
= 0;
267 str
= &line
->line
[1];
269 memset((char *) remap
, 0, sizeof(RemapSpec
));
271 while ((tok
= _XStrtok(str
, " ", strtok_buf
)) != NULL
) {
274 if (strcmp(tok
, "=") == 0)
276 for (i
= 0; i
< MAX_WORDS
; i
++) {
277 len
= strlen(cname
[i
]);
278 if (strncmp(cname
[i
], tok
, len
) == 0) {
279 if (strlen(tok
) > len
) {
280 char *end
= get_index(tok
+ len
, &ndx
);
282 if ((i
!= LAYOUT
&& i
!= VARIANT
) ||
283 *end
!= '\0' || ndx
== -1)
285 if (ndx
< 1 || ndx
> XkbNumKbdGroups
) {
286 DebugF("Illegal %s index: %d\n", cname
[i
], ndx
);
287 DebugF("Index must be in range 1..%d\n",
296 if (present
& (1 << i
)) {
297 if ((i
== LAYOUT
&& l_ndx_present
& (1 << ndx
)) ||
298 (i
== VARIANT
&& v_ndx_present
& (1 << ndx
))) {
299 DebugF("Component \"%s\" listed twice\n", tok
);
300 DebugF("Second definition ignored\n");
306 l_ndx_present
|= 1 << ndx
;
308 v_ndx_present
|= 1 << ndx
;
309 remap
->remap
[remap
->num_remap
].word
= i
;
310 remap
->remap
[remap
->num_remap
++].index
= ndx
;
315 fprintf(stderr
, "Unknown component \"%s\" ignored\n", tok
);
318 if ((present
& PART_MASK
) == 0) {
319 unsigned mask
= PART_MASK
;
321 ErrorF("Mapping needs at least one of ");
322 for (i
= 0; (i
< MAX_WORDS
); i
++) {
323 if ((1L << i
) & mask
) {
326 DebugF("\"%s,\" ", cname
[i
]);
328 DebugF("or \"%s\"\n", cname
[i
]);
331 DebugF("Illegal mapping ignored\n");
332 remap
->num_remap
= 0;
335 if ((present
& COMPONENT_MASK
) == 0) {
336 DebugF("Mapping needs at least one component\n");
337 DebugF("Illegal mapping ignored\n");
338 remap
->num_remap
= 0;
346 MatchOneOf(char *wanted
, char *vals_defined
)
349 int want_len
= strlen(wanted
);
351 for (str
= vals_defined
, next
= NULL
; str
!= NULL
; str
= next
) {
354 next
= strchr(str
, ',');
362 if ((len
== want_len
) && (strncmp(wanted
, str
, len
) == 0))
368 /***====================================================================***/
371 CheckLine(InputLine
* line
,
372 RemapSpec
* remap
, XkbRF_RulePtr rule
, XkbRF_GroupPtr group
)
375 register int nread
, i
;
377 _Xstrtokparams strtok_buf
;
380 if (line
->line
[0] == '!') {
381 if (line
->line
[1] == '$' ||
382 (line
->line
[1] == ' ' && line
->line
[2] == '$')) {
383 char *gname
= strchr(line
->line
, '$');
384 char *words
= strchr(gname
, ' ');
389 for (; *words
; words
++) {
390 if (*words
!= '=' && *words
!= ' ')
395 group
->name
= Xstrdup(gname
);
396 group
->words
= Xstrdup(words
);
397 for (i
= 1, words
= group
->words
; *words
; words
++) {
407 SetUpRemap(line
, remap
);
412 if (remap
->num_remap
== 0) {
413 DebugF("Must have a mapping before first line of data\n");
414 DebugF("Illegal line of data ignored\n");
417 memset((char *) &tmp
, 0, sizeof(FileSpec
));
419 for (nread
= 0; (tok
= _XStrtok(str
, " ", strtok_buf
)) != NULL
; nread
++) {
421 if (strcmp(tok
, "=") == 0) {
425 if (nread
> remap
->num_remap
) {
426 DebugF("Too many words on a line\n");
427 DebugF("Extra word \"%s\" ignored\n", tok
);
430 tmp
.name
[remap
->remap
[nread
].word
] = tok
;
431 if (*tok
== '+' || *tok
== '|')
434 if (nread
< remap
->num_remap
) {
435 DebugF("Too few words on a line: %s\n", line
->line
);
436 DebugF("line ignored\n");
441 rule
->number
= remap
->number
;
442 if (tmp
.name
[OPTION
])
443 rule
->flags
|= XkbRF_Option
;
445 rule
->flags
|= XkbRF_Append
;
447 rule
->flags
|= XkbRF_Normal
;
448 rule
->model
= Xstrdup(tmp
.name
[MODEL
]);
449 rule
->layout
= Xstrdup(tmp
.name
[LAYOUT
]);
450 rule
->variant
= Xstrdup(tmp
.name
[VARIANT
]);
451 rule
->option
= Xstrdup(tmp
.name
[OPTION
]);
453 rule
->keycodes
= Xstrdup(tmp
.name
[KEYCODES
]);
454 rule
->symbols
= Xstrdup(tmp
.name
[SYMBOLS
]);
455 rule
->types
= Xstrdup(tmp
.name
[TYPES
]);
456 rule
->compat
= Xstrdup(tmp
.name
[COMPAT
]);
457 rule
->geometry
= Xstrdup(tmp
.name
[GEOMETRY
]);
459 rule
->layout_num
= rule
->variant_num
= 0;
460 for (i
= 0; i
< nread
; i
++) {
461 if (remap
->remap
[i
].index
) {
462 if (remap
->remap
[i
].word
== LAYOUT
)
463 rule
->layout_num
= remap
->remap
[i
].index
;
464 if (remap
->remap
[i
].word
== VARIANT
)
465 rule
->variant_num
= remap
->remap
[i
].index
;
472 _Concat(char *str1
, char *str2
)
476 if ((!str1
) || (!str2
))
478 len
= strlen(str1
) + strlen(str2
) + 1;
479 str1
= realloc(str1
, len
* sizeof(char));
486 squeeze_spaces(char *p1
)
490 for (p2
= p1
; *p2
; p2
++) {
499 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs
, XkbRF_VarDefsPtr defs
)
502 memset((char *) mdefs
, 0, sizeof(XkbRF_MultiDefsRec
));
503 mdefs
->model
= defs
->model
;
504 mdefs
->options
= Xstrdup(defs
->options
);
506 squeeze_spaces(mdefs
->options
);
509 if (!strchr(defs
->layout
, ',')) {
510 mdefs
->layout
[0] = defs
->layout
;
516 mdefs
->layout
[1] = Xstrdup(defs
->layout
);
517 if (mdefs
->layout
[1] == NULL
)
519 squeeze_spaces(mdefs
->layout
[1]);
520 p
= mdefs
->layout
[1];
521 for (i
= 2; i
<= XkbNumKbdGroups
; i
++) {
522 if ((p
= strchr(p
, ','))) {
524 mdefs
->layout
[i
] = p
;
530 if (p
&& (p
= strchr(p
, ',')))
536 if (!strchr(defs
->variant
, ',')) {
537 mdefs
->variant
[0] = defs
->variant
;
543 mdefs
->variant
[1] = Xstrdup(defs
->variant
);
544 if (mdefs
->variant
[1] == NULL
)
546 squeeze_spaces(mdefs
->variant
[1]);
547 p
= mdefs
->variant
[1];
548 for (i
= 2; i
<= XkbNumKbdGroups
; i
++) {
549 if ((p
= strchr(p
, ','))) {
551 mdefs
->variant
[i
] = p
;
557 if (p
&& (p
= strchr(p
, ',')))
565 FreeMultiDefs(XkbRF_MultiDefsPtr defs
)
568 free(defs
->layout
[1]);
569 free(defs
->variant
[1]);
573 Apply(char *src
, char **dst
)
576 if (*src
== '+' || *src
== '!') {
577 *dst
= _Concat(*dst
, src
);
587 XkbRF_ApplyRule(XkbRF_RulePtr rule
, XkbComponentNamesPtr names
)
589 rule
->flags
&= ~XkbRF_PendingMatch
; /* clear the flag because it's applied */
591 Apply(rule
->keycodes
, &names
->keycodes
);
592 Apply(rule
->symbols
, &names
->symbols
);
593 Apply(rule
->types
, &names
->types
);
594 Apply(rule
->compat
, &names
->compat
);
595 Apply(rule
->geometry
, &names
->geometry
);
599 CheckGroup(XkbRF_RulesPtr rules
, char *group_name
, char *name
)
603 XkbRF_GroupPtr group
;
605 for (i
= 0, group
= rules
->groups
; i
< rules
->num_groups
; i
++, group
++) {
606 if (!strcmp(group
->name
, group_name
)) {
610 if (i
== rules
->num_groups
)
612 for (i
= 0, p
= group
->words
; i
< group
->number
; i
++, p
+= strlen(p
) + 1) {
613 if (!strcmp(p
, name
)) {
621 XkbRF_CheckApplyRule(XkbRF_RulePtr rule
,
622 XkbRF_MultiDefsPtr mdefs
,
623 XkbComponentNamesPtr names
, XkbRF_RulesPtr rules
)
625 Bool pending
= FALSE
;
627 if (rule
->model
!= NULL
) {
628 if (mdefs
->model
== NULL
)
630 if (strcmp(rule
->model
, "*") == 0) {
634 if (rule
->model
[0] == '$') {
635 if (!CheckGroup(rules
, rule
->model
, mdefs
->model
))
639 if (strcmp(rule
->model
, mdefs
->model
) != 0)
644 if (rule
->option
!= NULL
) {
645 if (mdefs
->options
== NULL
)
647 if ((!MatchOneOf(rule
->option
, mdefs
->options
)))
651 if (rule
->layout
!= NULL
) {
652 if (mdefs
->layout
[rule
->layout_num
] == NULL
||
653 *mdefs
->layout
[rule
->layout_num
] == '\0')
655 if (strcmp(rule
->layout
, "*") == 0) {
659 if (rule
->layout
[0] == '$') {
660 if (!CheckGroup(rules
, rule
->layout
,
661 mdefs
->layout
[rule
->layout_num
]))
665 if (strcmp(rule
->layout
, mdefs
->layout
[rule
->layout_num
]) != 0)
670 if (rule
->variant
!= NULL
) {
671 if (mdefs
->variant
[rule
->variant_num
] == NULL
||
672 *mdefs
->variant
[rule
->variant_num
] == '\0')
674 if (strcmp(rule
->variant
, "*") == 0) {
678 if (rule
->variant
[0] == '$') {
679 if (!CheckGroup(rules
, rule
->variant
,
680 mdefs
->variant
[rule
->variant_num
]))
684 if (strcmp(rule
->variant
,
685 mdefs
->variant
[rule
->variant_num
]) != 0)
691 rule
->flags
|= XkbRF_PendingMatch
;
694 /* exact match, apply it now */
695 XkbRF_ApplyRule(rule
, names
);
700 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules
)
705 for (i
= 0, rule
= rules
->rules
; i
< rules
->num_rules
; i
++, rule
++) {
706 rule
->flags
&= ~XkbRF_PendingMatch
;
711 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules
, XkbComponentNamesPtr names
)
716 for (rule
= rules
->rules
, i
= 0; i
< rules
->num_rules
; i
++, rule
++) {
717 if ((rule
->flags
& XkbRF_PendingMatch
) == 0)
719 XkbRF_ApplyRule(rule
, names
);
724 XkbRF_CheckApplyRules(XkbRF_RulesPtr rules
,
725 XkbRF_MultiDefsPtr mdefs
,
726 XkbComponentNamesPtr names
, int flags
)
732 for (rule
= rules
->rules
, i
= 0; i
< rules
->num_rules
; rule
++, i
++) {
733 if ((rule
->flags
& flags
) != flags
)
735 skip
= XkbRF_CheckApplyRule(rule
, mdefs
, names
, rules
);
736 if (skip
&& !(flags
& XkbRF_Option
)) {
737 for (; (i
< rules
->num_rules
) && (rule
->number
== skip
);
745 /***====================================================================***/
748 XkbRF_SubstituteVars(char *name
, XkbRF_MultiDefsPtr mdefs
)
750 char *str
, *outstr
, *orig
, *var
;
754 str
= index(name
, '%');
758 while (str
!= NULL
) {
762 if ((pfx
== '+') || (pfx
== '|') || (pfx
== '_') || (pfx
== '-')) {
766 else if (pfx
== '(') {
771 str
= get_index(var
+ 1, &ndx
);
773 str
= index(str
, '%');
776 if ((*var
== 'l') && mdefs
->layout
[ndx
] && *mdefs
->layout
[ndx
])
777 len
+= strlen(mdefs
->layout
[ndx
]) + extra_len
;
778 else if ((*var
== 'm') && mdefs
->model
)
779 len
+= strlen(mdefs
->model
) + extra_len
;
780 else if ((*var
== 'v') && mdefs
->variant
[ndx
] && *mdefs
->variant
[ndx
])
781 len
+= strlen(mdefs
->variant
[ndx
]) + extra_len
;
782 if ((pfx
== '(') && (*str
== ')')) {
785 str
= index(&str
[0], '%');
787 name
= malloc(len
+ 1);
790 while (*str
!= '\0') {
797 if ((pfx
== '+') || (pfx
== '|') || (pfx
== '_') || (pfx
== '-')) {
800 else if (pfx
== '(') {
808 str
= get_index(var
+ 1, &ndx
);
812 if ((*var
== 'l') && mdefs
->layout
[ndx
] && *mdefs
->layout
[ndx
]) {
815 strcpy(outstr
, mdefs
->layout
[ndx
]);
816 outstr
+= strlen(mdefs
->layout
[ndx
]);
820 else if ((*var
== 'm') && (mdefs
->model
)) {
823 strcpy(outstr
, mdefs
->model
);
824 outstr
+= strlen(mdefs
->model
);
828 else if ((*var
== 'v') && mdefs
->variant
[ndx
] &&
829 *mdefs
->variant
[ndx
]) {
832 strcpy(outstr
, mdefs
->variant
[ndx
]);
833 outstr
+= strlen(mdefs
->variant
[ndx
]);
837 if ((pfx
== '(') && (*str
== ')'))
850 /***====================================================================***/
853 XkbRF_GetComponents(XkbRF_RulesPtr rules
,
854 XkbRF_VarDefsPtr defs
, XkbComponentNamesPtr names
)
856 XkbRF_MultiDefsRec mdefs
;
858 MakeMultiDefs(&mdefs
, defs
);
860 memset((char *) names
, 0, sizeof(XkbComponentNamesRec
));
861 XkbRF_ClearPartialMatches(rules
);
862 XkbRF_CheckApplyRules(rules
, &mdefs
, names
, XkbRF_Normal
);
863 XkbRF_ApplyPartialMatches(rules
, names
);
864 XkbRF_CheckApplyRules(rules
, &mdefs
, names
, XkbRF_Append
);
865 XkbRF_ApplyPartialMatches(rules
, names
);
866 XkbRF_CheckApplyRules(rules
, &mdefs
, names
, XkbRF_Option
);
867 XkbRF_ApplyPartialMatches(rules
, names
);
870 names
->keycodes
= XkbRF_SubstituteVars(names
->keycodes
, &mdefs
);
872 names
->symbols
= XkbRF_SubstituteVars(names
->symbols
, &mdefs
);
874 names
->types
= XkbRF_SubstituteVars(names
->types
, &mdefs
);
876 names
->compat
= XkbRF_SubstituteVars(names
->compat
, &mdefs
);
878 names
->geometry
= XkbRF_SubstituteVars(names
->geometry
, &mdefs
);
880 FreeMultiDefs(&mdefs
);
881 return (names
->keycodes
&& names
->symbols
&& names
->types
&&
882 names
->compat
&& names
->geometry
);
886 XkbRF_AddRule(XkbRF_RulesPtr rules
)
888 if (rules
->sz_rules
< 1) {
889 rules
->sz_rules
= 16;
890 rules
->num_rules
= 0;
891 rules
->rules
= calloc(rules
->sz_rules
, sizeof(XkbRF_RuleRec
));
893 else if (rules
->num_rules
>= rules
->sz_rules
) {
894 rules
->sz_rules
*= 2;
895 rules
->rules
= realloc(rules
->rules
,
896 rules
->sz_rules
* sizeof(XkbRF_RuleRec
));
899 rules
->sz_rules
= rules
->num_rules
= 0;
900 DebugF("Allocation failure in XkbRF_AddRule\n");
903 memset((char *) &rules
->rules
[rules
->num_rules
], 0, sizeof(XkbRF_RuleRec
));
904 return &rules
->rules
[rules
->num_rules
++];
907 static XkbRF_GroupPtr
908 XkbRF_AddGroup(XkbRF_RulesPtr rules
)
910 if (rules
->sz_groups
< 1) {
911 rules
->sz_groups
= 16;
912 rules
->num_groups
= 0;
913 rules
->groups
= calloc(rules
->sz_groups
, sizeof(XkbRF_GroupRec
));
915 else if (rules
->num_groups
>= rules
->sz_groups
) {
916 rules
->sz_groups
*= 2;
917 rules
->groups
= realloc(rules
->groups
,
918 rules
->sz_groups
* sizeof(XkbRF_GroupRec
));
920 if (!rules
->groups
) {
921 rules
->sz_groups
= rules
->num_groups
= 0;
925 memset((char *) &rules
->groups
[rules
->num_groups
], 0,
926 sizeof(XkbRF_GroupRec
));
927 return &rules
->groups
[rules
->num_groups
++];
931 XkbRF_LoadRules(FILE * file
, XkbRF_RulesPtr rules
)
935 XkbRF_RuleRec trule
, *rule
;
936 XkbRF_GroupRec tgroup
, *group
;
938 if (!(rules
&& file
))
940 memset((char *) &remap
, 0, sizeof(RemapSpec
));
941 memset((char *) &tgroup
, 0, sizeof(XkbRF_GroupRec
));
942 InitInputLine(&line
);
943 while (GetInputLine(file
, &line
, TRUE
)) {
944 if (CheckLine(&line
, &remap
, &trule
, &tgroup
)) {
946 if ((group
= XkbRF_AddGroup(rules
)) != NULL
) {
948 memset((char *) &tgroup
, 0, sizeof(XkbRF_GroupRec
));
952 if ((rule
= XkbRF_AddRule(rules
)) != NULL
) {
954 memset((char *) &trule
, 0, sizeof(XkbRF_RuleRec
));
960 FreeInputLine(&line
);
965 XkbRF_LoadRulesByName(char *base
, char *locale
, XkbRF_RulesPtr rules
)
971 if ((!base
) || (!rules
))
974 if (snprintf(buf
, PATH_MAX
, "%s-%s", base
, locale
) >= PATH_MAX
)
978 if (strlen(base
) + 1 > PATH_MAX
)
983 file
= fopen(buf
, "r");
984 if ((!file
) && (locale
)) { /* fallback if locale was specified */
986 file
= fopen(buf
, "r");
990 ok
= XkbRF_LoadRules(file
, rules
);
995 /***====================================================================***/
1000 return calloc(1, sizeof(XkbRF_RulesRec
));
1003 /***====================================================================***/
1006 XkbRF_Free(XkbRF_RulesPtr rules
, Bool freeRules
)
1010 XkbRF_GroupPtr group
;
1015 for (i
= 0, rule
= rules
->rules
; i
< rules
->num_rules
; i
++, rule
++) {
1018 free(rule
->variant
);
1020 free(rule
->keycodes
);
1021 free(rule
->symbols
);
1024 free(rule
->geometry
);
1025 memset((char *) rule
, 0, sizeof(XkbRF_RuleRec
));
1028 rules
->num_rules
= rules
->sz_rules
= 0;
1029 rules
->rules
= NULL
;
1032 if (rules
->groups
) {
1033 for (i
= 0, group
= rules
->groups
; i
< rules
->num_groups
; i
++, group
++) {
1037 free(rules
->groups
);
1038 rules
->num_groups
= 0;
1039 rules
->groups
= NULL
;