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
57 typedef 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
65 static void
InitInputLine(InputLine * line)66 InitInputLine(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
75 static void
FreeInputLine(InputLine * line)76 FreeInputLine(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
87 static int
InputLineAddChar(InputLine * line,int ch)88 InputLineAddChar(InputLine * line, int ch)
89 {
90 if (line->num_line >= line->sz_line) {
91 if (line->line == line->buf) {
92 line->line = xallocarray(line->sz_line, 2);
93 memcpy(line->line, line->buf, line->sz_line);
94 }
95 else {
96 line->line = reallocarray(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
108 static Bool
GetInputLine(FILE * file,InputLine * line,Bool checkbang)109 GetInputLine(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
201 static const char *cname[MAX_WORDS] = {
202 "model", "layout", "variant", "option",
203 "keycodes", "symbols", "types", "compat", "geometry"
204 };
205
206 typedef struct _RemapSpec {
207 int number;
208 int num_remap;
209 struct {
210 int word;
211 int index;
212 } remap[MAX_WORDS];
213 } RemapSpec;
214
215 typedef struct _FileSpec {
216 char *name[MAX_WORDS];
217 struct _FileSpec *pending;
218 } FileSpec;
219
220 typedef struct {
221 const char *model;
222 const char *layout[XkbNumKbdGroups + 1];
223 const char *variant[XkbNumKbdGroups + 1];
224 const char *options;
225 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
226
227 #define NDX_BUFF_SIZE 4
228
229 /***====================================================================***/
230
231 static char *
get_index(char * str,int * ndx)232 get_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
256 static void
SetUpRemap(InputLine * line,RemapSpec * remap)257 SetUpRemap(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
345 static Bool
MatchOneOf(const char * wanted,const char * vals_defined)346 MatchOneOf(const char *wanted, const char *vals_defined)
347 {
348 const 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
370 static Bool
CheckLine(InputLine * line,RemapSpec * remap,XkbRF_RulePtr rule,XkbRF_GroupPtr group)371 CheckLine(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
471 static char *
_Concat(char * str1,const char * str2)472 _Concat(char *str1, const 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
485 static void
squeeze_spaces(char * p1)486 squeeze_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
498 static Bool
MakeMultiDefs(XkbRF_MultiDefsPtr mdefs,XkbRF_VarDefsPtr defs)499 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
500 {
501 char *options;
502 memset((char *) mdefs, 0, sizeof(XkbRF_MultiDefsRec));
503 mdefs->model = defs->model;
504 options = Xstrdup(defs->options);
505 if (options)
506 squeeze_spaces(options);
507 mdefs->options = options;
508
509 if (defs->layout) {
510 if (!strchr(defs->layout, ',')) {
511 mdefs->layout[0] = defs->layout;
512 }
513 else {
514 char *p;
515 char *layout;
516 int i;
517
518 layout = Xstrdup(defs->layout);
519 if (layout == NULL)
520 return FALSE;
521 squeeze_spaces(layout);
522 mdefs->layout[1] = layout;
523 p = layout;
524 for (i = 2; i <= XkbNumKbdGroups; i++) {
525 if ((p = strchr(p, ','))) {
526 *p++ = '\0';
527 mdefs->layout[i] = p;
528 }
529 else {
530 break;
531 }
532 }
533 if (p && (p = strchr(p, ',')))
534 *p = '\0';
535 }
536 }
537
538 if (defs->variant) {
539 if (!strchr(defs->variant, ',')) {
540 mdefs->variant[0] = defs->variant;
541 }
542 else {
543 char *p;
544 char *variant;
545 int i;
546
547 variant = Xstrdup(defs->variant);
548 if (variant == NULL)
549 return FALSE;
550 squeeze_spaces(variant);
551 mdefs->variant[1] = variant;
552 p = variant;
553 for (i = 2; i <= XkbNumKbdGroups; i++) {
554 if ((p = strchr(p, ','))) {
555 *p++ = '\0';
556 mdefs->variant[i] = p;
557 }
558 else {
559 break;
560 }
561 }
562 if (p && (p = strchr(p, ',')))
563 *p = '\0';
564 }
565 }
566 return TRUE;
567 }
568
569 static void
FreeMultiDefs(XkbRF_MultiDefsPtr defs)570 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
571 {
572 free((void *) defs->options);
573 free((void *) defs->layout[1]);
574 free((void *) defs->variant[1]);
575 }
576
577 static void
Apply(const char * src,char ** dst)578 Apply(const char *src, char **dst)
579 {
580 if (src) {
581 if (*src == '+' || *src == '|') {
582 *dst = _Concat(*dst, src);
583 }
584 else {
585 if (*dst == NULL)
586 *dst = Xstrdup(src);
587 }
588 }
589 }
590
591 static void
XkbRF_ApplyRule(XkbRF_RulePtr rule,XkbComponentNamesPtr names)592 XkbRF_ApplyRule(XkbRF_RulePtr rule, XkbComponentNamesPtr names)
593 {
594 rule->flags &= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
595
596 Apply(rule->keycodes, &names->keycodes);
597 Apply(rule->symbols, &names->symbols);
598 Apply(rule->types, &names->types);
599 Apply(rule->compat, &names->compat);
600 Apply(rule->geometry, &names->geometry);
601 }
602
603 static Bool
CheckGroup(XkbRF_RulesPtr rules,const char * group_name,const char * name)604 CheckGroup(XkbRF_RulesPtr rules, const char *group_name, const char *name)
605 {
606 int i;
607 char *p;
608 XkbRF_GroupPtr group;
609
610 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
611 if (!strcmp(group->name, group_name)) {
612 break;
613 }
614 }
615 if (i == rules->num_groups)
616 return FALSE;
617 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p) + 1) {
618 if (!strcmp(p, name)) {
619 return TRUE;
620 }
621 }
622 return FALSE;
623 }
624
625 static int
XkbRF_CheckApplyRule(XkbRF_RulePtr rule,XkbRF_MultiDefsPtr mdefs,XkbComponentNamesPtr names,XkbRF_RulesPtr rules)626 XkbRF_CheckApplyRule(XkbRF_RulePtr rule,
627 XkbRF_MultiDefsPtr mdefs,
628 XkbComponentNamesPtr names, XkbRF_RulesPtr rules)
629 {
630 Bool pending = FALSE;
631
632 if (rule->model != NULL) {
633 if (mdefs->model == NULL)
634 return 0;
635 if (strcmp(rule->model, "*") == 0) {
636 pending = TRUE;
637 }
638 else {
639 if (rule->model[0] == '$') {
640 if (!CheckGroup(rules, rule->model, mdefs->model))
641 return 0;
642 }
643 else {
644 if (strcmp(rule->model, mdefs->model) != 0)
645 return 0;
646 }
647 }
648 }
649 if (rule->option != NULL) {
650 if (mdefs->options == NULL)
651 return 0;
652 if ((!MatchOneOf(rule->option, mdefs->options)))
653 return 0;
654 }
655
656 if (rule->layout != NULL) {
657 if (mdefs->layout[rule->layout_num] == NULL ||
658 *mdefs->layout[rule->layout_num] == '\0')
659 return 0;
660 if (strcmp(rule->layout, "*") == 0) {
661 pending = TRUE;
662 }
663 else {
664 if (rule->layout[0] == '$') {
665 if (!CheckGroup(rules, rule->layout,
666 mdefs->layout[rule->layout_num]))
667 return 0;
668 }
669 else {
670 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
671 return 0;
672 }
673 }
674 }
675 if (rule->variant != NULL) {
676 if (mdefs->variant[rule->variant_num] == NULL ||
677 *mdefs->variant[rule->variant_num] == '\0')
678 return 0;
679 if (strcmp(rule->variant, "*") == 0) {
680 pending = TRUE;
681 }
682 else {
683 if (rule->variant[0] == '$') {
684 if (!CheckGroup(rules, rule->variant,
685 mdefs->variant[rule->variant_num]))
686 return 0;
687 }
688 else {
689 if (strcmp(rule->variant,
690 mdefs->variant[rule->variant_num]) != 0)
691 return 0;
692 }
693 }
694 }
695 if (pending) {
696 rule->flags |= XkbRF_PendingMatch;
697 return rule->number;
698 }
699 /* exact match, apply it now */
700 XkbRF_ApplyRule(rule, names);
701 return rule->number;
702 }
703
704 static void
XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)705 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
706 {
707 register int i;
708 XkbRF_RulePtr rule;
709
710 for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) {
711 rule->flags &= ~XkbRF_PendingMatch;
712 }
713 }
714
715 static void
XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names)716 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules, XkbComponentNamesPtr names)
717 {
718 int i;
719 XkbRF_RulePtr rule;
720
721 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
722 if ((rule->flags & XkbRF_PendingMatch) == 0)
723 continue;
724 XkbRF_ApplyRule(rule, names);
725 }
726 }
727
728 static void
XkbRF_CheckApplyRules(XkbRF_RulesPtr rules,XkbRF_MultiDefsPtr mdefs,XkbComponentNamesPtr names,int flags)729 XkbRF_CheckApplyRules(XkbRF_RulesPtr rules,
730 XkbRF_MultiDefsPtr mdefs,
731 XkbComponentNamesPtr names, int flags)
732 {
733 int i;
734 XkbRF_RulePtr rule;
735 int skip;
736
737 for (rule = rules->rules, i = 0; i < rules->num_rules; rule++, i++) {
738 if ((rule->flags & flags) != flags)
739 continue;
740 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
741 if (skip && !(flags & XkbRF_Option)) {
742 for (; (i < rules->num_rules) && (rule->number == skip);
743 rule++, i++);
744 rule--;
745 i--;
746 }
747 }
748 }
749
750 /***====================================================================***/
751
752 static char *
XkbRF_SubstituteVars(char * name,XkbRF_MultiDefsPtr mdefs)753 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
754 {
755 char *str, *outstr, *orig, *var;
756 int len, ndx;
757
758 orig = name;
759 str = index(name, '%');
760 if (str == NULL)
761 return name;
762 len = strlen(name);
763 while (str != NULL) {
764 char pfx = str[1];
765 int extra_len = 0;
766
767 if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) {
768 extra_len = 1;
769 str++;
770 }
771 else if (pfx == '(') {
772 extra_len = 2;
773 str++;
774 }
775 var = str + 1;
776 str = get_index(var + 1, &ndx);
777 if (ndx == -1) {
778 str = index(str, '%');
779 continue;
780 }
781 if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
782 len += strlen(mdefs->layout[ndx]) + extra_len;
783 else if ((*var == 'm') && mdefs->model)
784 len += strlen(mdefs->model) + extra_len;
785 else if ((*var == 'v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
786 len += strlen(mdefs->variant[ndx]) + extra_len;
787 if ((pfx == '(') && (*str == ')')) {
788 str++;
789 }
790 str = index(&str[0], '%');
791 }
792 name = malloc(len + 1);
793 str = orig;
794 outstr = name;
795 while (*str != '\0') {
796 if (str[0] == '%') {
797 char pfx, sfx;
798
799 str++;
800 pfx = str[0];
801 sfx = '\0';
802 if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) {
803 str++;
804 }
805 else if (pfx == '(') {
806 sfx = ')';
807 str++;
808 }
809 else
810 pfx = '\0';
811
812 var = str;
813 str = get_index(var + 1, &ndx);
814 if (ndx == -1) {
815 continue;
816 }
817 if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
818 if (pfx)
819 *outstr++ = pfx;
820 strcpy(outstr, mdefs->layout[ndx]);
821 outstr += strlen(mdefs->layout[ndx]);
822 if (sfx)
823 *outstr++ = sfx;
824 }
825 else if ((*var == 'm') && (mdefs->model)) {
826 if (pfx)
827 *outstr++ = pfx;
828 strcpy(outstr, mdefs->model);
829 outstr += strlen(mdefs->model);
830 if (sfx)
831 *outstr++ = sfx;
832 }
833 else if ((*var == 'v') && mdefs->variant[ndx] &&
834 *mdefs->variant[ndx]) {
835 if (pfx)
836 *outstr++ = pfx;
837 strcpy(outstr, mdefs->variant[ndx]);
838 outstr += strlen(mdefs->variant[ndx]);
839 if (sfx)
840 *outstr++ = sfx;
841 }
842 if ((pfx == '(') && (*str == ')'))
843 str++;
844 }
845 else {
846 *outstr++ = *str++;
847 }
848 }
849 *outstr++ = '\0';
850 if (orig != name)
851 free(orig);
852 return name;
853 }
854
855 /***====================================================================***/
856
857 Bool
XkbRF_GetComponents(XkbRF_RulesPtr rules,XkbRF_VarDefsPtr defs,XkbComponentNamesPtr names)858 XkbRF_GetComponents(XkbRF_RulesPtr rules,
859 XkbRF_VarDefsPtr defs, XkbComponentNamesPtr names)
860 {
861 XkbRF_MultiDefsRec mdefs;
862
863 MakeMultiDefs(&mdefs, defs);
864
865 memset((char *) names, 0, sizeof(XkbComponentNamesRec));
866 XkbRF_ClearPartialMatches(rules);
867 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
868 XkbRF_ApplyPartialMatches(rules, names);
869 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
870 XkbRF_ApplyPartialMatches(rules, names);
871 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
872 XkbRF_ApplyPartialMatches(rules, names);
873
874 if (names->keycodes)
875 names->keycodes = XkbRF_SubstituteVars(names->keycodes, &mdefs);
876 if (names->symbols)
877 names->symbols = XkbRF_SubstituteVars(names->symbols, &mdefs);
878 if (names->types)
879 names->types = XkbRF_SubstituteVars(names->types, &mdefs);
880 if (names->compat)
881 names->compat = XkbRF_SubstituteVars(names->compat, &mdefs);
882 if (names->geometry)
883 names->geometry = XkbRF_SubstituteVars(names->geometry, &mdefs);
884
885 FreeMultiDefs(&mdefs);
886 return (names->keycodes && names->symbols && names->types &&
887 names->compat && names->geometry);
888 }
889
890 static XkbRF_RulePtr
XkbRF_AddRule(XkbRF_RulesPtr rules)891 XkbRF_AddRule(XkbRF_RulesPtr rules)
892 {
893 if (rules->sz_rules < 1) {
894 rules->sz_rules = 16;
895 rules->num_rules = 0;
896 rules->rules = calloc(rules->sz_rules, sizeof(XkbRF_RuleRec));
897 }
898 else if (rules->num_rules >= rules->sz_rules) {
899 rules->sz_rules *= 2;
900 rules->rules = reallocarray(rules->rules,
901 rules->sz_rules, sizeof(XkbRF_RuleRec));
902 }
903 if (!rules->rules) {
904 rules->sz_rules = rules->num_rules = 0;
905 DebugF("Allocation failure in XkbRF_AddRule\n");
906 return NULL;
907 }
908 memset((char *) &rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
909 return &rules->rules[rules->num_rules++];
910 }
911
912 static XkbRF_GroupPtr
XkbRF_AddGroup(XkbRF_RulesPtr rules)913 XkbRF_AddGroup(XkbRF_RulesPtr rules)
914 {
915 if (rules->sz_groups < 1) {
916 rules->sz_groups = 16;
917 rules->num_groups = 0;
918 rules->groups = calloc(rules->sz_groups, sizeof(XkbRF_GroupRec));
919 }
920 else if (rules->num_groups >= rules->sz_groups) {
921 rules->sz_groups *= 2;
922 rules->groups = reallocarray(rules->groups,
923 rules->sz_groups, sizeof(XkbRF_GroupRec));
924 }
925 if (!rules->groups) {
926 rules->sz_groups = rules->num_groups = 0;
927 return NULL;
928 }
929
930 memset((char *) &rules->groups[rules->num_groups], 0,
931 sizeof(XkbRF_GroupRec));
932 return &rules->groups[rules->num_groups++];
933 }
934
935 Bool
XkbRF_LoadRules(FILE * file,XkbRF_RulesPtr rules)936 XkbRF_LoadRules(FILE * file, XkbRF_RulesPtr rules)
937 {
938 InputLine line;
939 RemapSpec remap;
940 XkbRF_RuleRec trule, *rule;
941 XkbRF_GroupRec tgroup, *group;
942
943 if (!(rules && file))
944 return FALSE;
945 memset((char *) &remap, 0, sizeof(RemapSpec));
946 memset((char *) &tgroup, 0, sizeof(XkbRF_GroupRec));
947 InitInputLine(&line);
948 while (GetInputLine(file, &line, TRUE)) {
949 if (CheckLine(&line, &remap, &trule, &tgroup)) {
950 if (tgroup.number) {
951 if ((group = XkbRF_AddGroup(rules)) != NULL) {
952 *group = tgroup;
953 memset((char *) &tgroup, 0, sizeof(XkbRF_GroupRec));
954 }
955 }
956 else {
957 if ((rule = XkbRF_AddRule(rules)) != NULL) {
958 *rule = trule;
959 memset((char *) &trule, 0, sizeof(XkbRF_RuleRec));
960 }
961 }
962 }
963 line.num_line = 0;
964 }
965 FreeInputLine(&line);
966 return TRUE;
967 }
968
969 Bool
XkbRF_LoadRulesByName(char * base,char * locale,XkbRF_RulesPtr rules)970 XkbRF_LoadRulesByName(char *base, char *locale, XkbRF_RulesPtr rules)
971 {
972 FILE *file;
973 char buf[PATH_MAX];
974 Bool ok;
975
976 if ((!base) || (!rules))
977 return FALSE;
978 if (locale) {
979 if (snprintf(buf, PATH_MAX, "%s-%s", base, locale) >= PATH_MAX)
980 return FALSE;
981 }
982 else {
983 if (strlen(base) + 1 > PATH_MAX)
984 return FALSE;
985 strcpy(buf, base);
986 }
987
988 file = fopen(buf, "r");
989 if ((!file) && (locale)) { /* fallback if locale was specified */
990 strcpy(buf, base);
991 file = fopen(buf, "r");
992 }
993 if (!file)
994 return FALSE;
995 ok = XkbRF_LoadRules(file, rules);
996 fclose(file);
997 return ok;
998 }
999
1000 /***====================================================================***/
1001
1002 XkbRF_RulesPtr
XkbRF_Create(void)1003 XkbRF_Create(void)
1004 {
1005 return calloc(1, sizeof(XkbRF_RulesRec));
1006 }
1007
1008 /***====================================================================***/
1009
1010 void
XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules)1011 XkbRF_Free(XkbRF_RulesPtr rules, Bool freeRules)
1012 {
1013 int i;
1014 XkbRF_RulePtr rule;
1015 XkbRF_GroupPtr group;
1016
1017 if (!rules)
1018 return;
1019 if (rules->rules) {
1020 for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) {
1021 free((void *) rule->model);
1022 free((void *) rule->layout);
1023 free((void *) rule->variant);
1024 free((void *) rule->option);
1025 free((void *) rule->keycodes);
1026 free((void *) rule->symbols);
1027 free((void *) rule->types);
1028 free((void *) rule->compat);
1029 free((void *) rule->geometry);
1030 memset((char *) rule, 0, sizeof(XkbRF_RuleRec));
1031 }
1032 free(rules->rules);
1033 rules->num_rules = rules->sz_rules = 0;
1034 rules->rules = NULL;
1035 }
1036
1037 if (rules->groups) {
1038 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
1039 free((void *) group->name);
1040 free(group->words);
1041 }
1042 free(rules->groups);
1043 rules->num_groups = 0;
1044 rules->groups = NULL;
1045 }
1046 if (freeRules)
1047 free(rules);
1048 return;
1049 }
1050