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