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