First import
[xorg_rtime.git] / xorg-server-1.4 / xkb / maprules.c
blob0fa356ee57c9111056625cf44095d4b1ffba09a8
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 #define NEED_EVENTS
40 #include <X11/Xproto.h>
41 #include <X11/X.h>
42 #include <X11/Xos.h>
43 #include <X11/Xfuncs.h>
44 #include <X11/Xatom.h>
45 #include <X11/keysym.h>
46 #include "misc.h"
47 #include "inputstr.h"
48 #include "dix.h"
49 #include <X11/extensions/XKBstr.h>
50 #define XKBSRV_NEED_FILE_FUNCS
51 #include <xkbsrv.h>
53 #ifdef DEBUG
54 #define PR_DEBUG(s) fprintf(stderr,s)
55 #define PR_DEBUG1(s,a) fprintf(stderr,s,a)
56 #define PR_DEBUG2(s,a,b) fprintf(stderr,s,a,b)
57 #else
58 #define PR_DEBUG(s)
59 #define PR_DEBUG1(s,a)
60 #define PR_DEBUG2(s,a,b)
61 #endif
63 /***====================================================================***/
65 #define DFLT_LINE_SIZE 128
67 typedef struct {
68 int line_num;
69 int sz_line;
70 int num_line;
71 char buf[DFLT_LINE_SIZE];
72 char * line;
73 } InputLine;
75 static void
76 InitInputLine(InputLine *line)
78 line->line_num= 1;
79 line->num_line= 0;
80 line->sz_line= DFLT_LINE_SIZE;
81 line->line= line->buf;
82 return;
85 static void
86 FreeInputLine(InputLine *line)
88 if (line->line!=line->buf)
89 _XkbFree(line->line);
90 line->line_num= 1;
91 line->num_line= 0;
92 line->sz_line= DFLT_LINE_SIZE;
93 line->line= line->buf;
94 return;
97 static int
98 InputLineAddChar(InputLine *line,int ch)
100 if (line->num_line>=line->sz_line) {
101 if (line->line==line->buf) {
102 line->line= (char *)_XkbAlloc(line->sz_line*2);
103 memcpy(line->line,line->buf,line->sz_line);
105 else {
106 line->line=(char *)_XkbRealloc((char *)line->line,line->sz_line*2);
108 line->sz_line*= 2;
110 line->line[line->num_line++]= ch;
111 return ch;
114 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
115 (int)((l)->line[(l)->num_line++]= (c)):\
116 InputLineAddChar(l,c))
118 static Bool
119 GetInputLine(FILE *file,InputLine *line,Bool checkbang)
121 int ch;
122 Bool endOfFile,spacePending,slashPending,inComment;
124 endOfFile= False;
125 while ((!endOfFile)&&(line->num_line==0)) {
126 spacePending= slashPending= inComment= False;
127 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
128 if (ch=='\\') {
129 if ((ch=getc(file))==EOF)
130 break;
131 if (ch=='\n') {
132 inComment= False;
133 ch= ' ';
134 line->line_num++;
137 if (inComment)
138 continue;
139 if (ch=='/') {
140 if (slashPending) {
141 inComment= True;
142 slashPending= False;
144 else {
145 slashPending= True;
147 continue;
149 else if (slashPending) {
150 if (spacePending) {
151 ADD_CHAR(line,' ');
152 spacePending= False;
154 ADD_CHAR(line,'/');
155 slashPending= False;
157 if (isspace(ch)) {
158 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
159 ch= getc(file);
161 if (ch==EOF)
162 break;
163 if ((ch!='\n')&&(line->num_line>0))
164 spacePending= True;
165 ungetc(ch,file);
167 else {
168 if (spacePending) {
169 ADD_CHAR(line,' ');
170 spacePending= False;
172 if (checkbang && ch=='!') {
173 if (line->num_line!=0) {
174 PR_DEBUG("The '!' legal only at start of line\n");
175 PR_DEBUG("Line containing '!' ignored\n");
176 line->num_line= 0;
177 inComment= 0;
178 break;
182 ADD_CHAR(line,ch);
185 if (ch==EOF)
186 endOfFile= True;
187 /* else line->num_line++;*/
189 if ((line->num_line==0)&&(endOfFile))
190 return False;
191 ADD_CHAR(line,'\0');
192 return True;
195 /***====================================================================***/
197 #define MODEL 0
198 #define LAYOUT 1
199 #define VARIANT 2
200 #define OPTION 3
201 #define KEYCODES 4
202 #define SYMBOLS 5
203 #define TYPES 6
204 #define COMPAT 7
205 #define GEOMETRY 8
206 #define KEYMAP 9
207 #define MAX_WORDS 10
209 #define PART_MASK 0x000F
210 #define COMPONENT_MASK 0x03F0
212 static char * cname[MAX_WORDS] = {
213 "model", "layout", "variant", "option",
214 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
217 typedef struct _RemapSpec {
218 int number;
219 int num_remap;
220 struct {
221 int word;
222 int index;
223 } remap[MAX_WORDS];
224 } RemapSpec;
226 typedef struct _FileSpec {
227 char * name[MAX_WORDS];
228 struct _FileSpec * pending;
229 } FileSpec;
231 typedef struct {
232 char * model;
233 char * layout[XkbNumKbdGroups+1];
234 char * variant[XkbNumKbdGroups+1];
235 char * options;
236 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
238 #define NDX_BUFF_SIZE 4
240 /***====================================================================***/
242 static char*
243 get_index(char *str, int *ndx)
245 char ndx_buf[NDX_BUFF_SIZE];
246 char *end;
248 if (*str != '[') {
249 *ndx = 0;
250 return str;
252 str++;
253 end = strchr(str, ']');
254 if (end == NULL) {
255 *ndx = -1;
256 return str - 1;
258 if ( (end - str) >= NDX_BUFF_SIZE) {
259 *ndx = -1;
260 return end + 1;
262 strncpy(ndx_buf, str, end - str);
263 ndx_buf[end - str] = '\0';
264 *ndx = atoi(ndx_buf);
265 return end + 1;
268 static void
269 SetUpRemap(InputLine *line,RemapSpec *remap)
271 char * tok,*str;
272 unsigned present, l_ndx_present, v_ndx_present;
273 register int i;
274 int len, ndx;
275 _Xstrtokparams strtok_buf;
276 #ifdef DEBUG
277 Bool found;
278 #endif
281 l_ndx_present = v_ndx_present = present= 0;
282 str= &line->line[1];
283 len = remap->number;
284 bzero((char *)remap,sizeof(RemapSpec));
285 remap->number = len;
286 while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
287 #ifdef DEBUG
288 found= False;
289 #endif
290 str= NULL;
291 if (strcmp(tok,"=")==0)
292 continue;
293 for (i=0;i<MAX_WORDS;i++) {
294 len = strlen(cname[i]);
295 if (strncmp(cname[i],tok,len)==0) {
296 if(strlen(tok) > len) {
297 char *end = get_index(tok+len, &ndx);
298 if ((i != LAYOUT && i != VARIANT) ||
299 *end != '\0' || ndx == -1)
300 break;
301 if (ndx < 1 || ndx > XkbNumKbdGroups) {
302 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
303 PR_DEBUG1("Index must be in range 1..%d\n",
304 XkbNumKbdGroups);
305 break;
307 } else {
308 ndx = 0;
310 #ifdef DEBUG
311 found= True;
312 #endif
313 if (present&(1<<i)) {
314 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
315 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
316 PR_DEBUG1("Component \"%s\" listed twice\n",tok);
317 PR_DEBUG("Second definition ignored\n");
318 break;
321 present |= (1<<i);
322 if (i == LAYOUT)
323 l_ndx_present |= 1 << ndx;
324 if (i == VARIANT)
325 v_ndx_present |= 1 << ndx;
326 remap->remap[remap->num_remap].word= i;
327 remap->remap[remap->num_remap++].index= ndx;
328 break;
331 #ifdef DEBUG
332 if (!found) {
333 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
335 #endif
337 if ((present&PART_MASK)==0) {
338 #ifdef DEBUG
339 unsigned mask= PART_MASK;
340 fprintf(stderr,"Mapping needs at least one of ");
341 for (i=0; (i<MAX_WORDS); i++) {
342 if ((1L<<i)&mask) {
343 mask&= ~(1L<<i);
344 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
345 else fprintf(stderr,"or \"%s\"\n",cname[i]);
348 fprintf(stderr,"Illegal mapping ignored\n");
349 #endif
350 remap->num_remap= 0;
351 return;
353 if ((present&COMPONENT_MASK)==0) {
354 PR_DEBUG("Mapping needs at least one component\n");
355 PR_DEBUG("Illegal mapping ignored\n");
356 remap->num_remap= 0;
357 return;
359 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
360 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
361 PR_DEBUG("Keymap cannot appear with other components\n");
362 PR_DEBUG("Illegal mapping ignored\n");
363 remap->num_remap= 0;
364 return;
366 remap->number++;
367 return;
370 static Bool
371 MatchOneOf(char *wanted,char *vals_defined)
373 char *str,*next;
374 int want_len= strlen(wanted);
376 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
377 int len;
378 next= strchr(str,',');
379 if (next) {
380 len= next-str;
381 next++;
383 else {
384 len= strlen(str);
386 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
387 return True;
389 return False;
392 /***====================================================================***/
394 static Bool
395 CheckLine( InputLine * line,
396 RemapSpec * remap,
397 XkbRF_RulePtr rule,
398 XkbRF_GroupPtr group)
400 char * str,*tok;
401 register int nread, i;
402 FileSpec tmp;
403 _Xstrtokparams strtok_buf;
404 Bool append = False;
406 if (line->line[0]=='!') {
407 if (line->line[1] == '$' ||
408 (line->line[1] == ' ' && line->line[2] == '$')) {
409 char *gname = strchr(line->line, '$');
410 char *words = strchr(gname, ' ');
411 if(!words)
412 return False;
413 *words++ = '\0';
414 for (; *words; words++) {
415 if (*words != '=' && *words != ' ')
416 break;
418 if (*words == '\0')
419 return False;
420 group->name = _XkbDupString(gname);
421 group->words = _XkbDupString(words);
422 for (i = 1, words = group->words; *words; words++) {
423 if ( *words == ' ') {
424 *words++ = '\0';
425 i++;
428 group->number = i;
429 return True;
430 } else {
431 SetUpRemap(line,remap);
432 return False;
436 if (remap->num_remap==0) {
437 PR_DEBUG("Must have a mapping before first line of data\n");
438 PR_DEBUG("Illegal line of data ignored\n");
439 return False;
441 bzero((char *)&tmp,sizeof(FileSpec));
442 str= line->line;
443 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
444 str= NULL;
445 if (strcmp(tok,"=")==0) {
446 nread--;
447 continue;
449 if (nread>remap->num_remap) {
450 PR_DEBUG("Too many words on a line\n");
451 PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
452 continue;
454 tmp.name[remap->remap[nread].word]= tok;
455 if (*tok == '+' || *tok == '|')
456 append = True;
458 if (nread<remap->num_remap) {
459 PR_DEBUG1("Too few words on a line: %s\n", line->line);
460 PR_DEBUG("line ignored\n");
461 return False;
464 rule->flags= 0;
465 rule->number = remap->number;
466 if (tmp.name[OPTION])
467 rule->flags|= XkbRF_Option;
468 else if (append)
469 rule->flags|= XkbRF_Append;
470 else
471 rule->flags|= XkbRF_Normal;
472 rule->model= _XkbDupString(tmp.name[MODEL]);
473 rule->layout= _XkbDupString(tmp.name[LAYOUT]);
474 rule->variant= _XkbDupString(tmp.name[VARIANT]);
475 rule->option= _XkbDupString(tmp.name[OPTION]);
477 rule->keycodes= _XkbDupString(tmp.name[KEYCODES]);
478 rule->symbols= _XkbDupString(tmp.name[SYMBOLS]);
479 rule->types= _XkbDupString(tmp.name[TYPES]);
480 rule->compat= _XkbDupString(tmp.name[COMPAT]);
481 rule->geometry= _XkbDupString(tmp.name[GEOMETRY]);
482 rule->keymap= _XkbDupString(tmp.name[KEYMAP]);
484 rule->layout_num = rule->variant_num = 0;
485 for (i = 0; i < nread; i++) {
486 if (remap->remap[i].index) {
487 if (remap->remap[i].word == LAYOUT)
488 rule->layout_num = remap->remap[i].index;
489 if (remap->remap[i].word == VARIANT)
490 rule->variant_num = remap->remap[i].index;
493 return True;
496 static char *
497 _Concat(char *str1,char *str2)
499 int len;
501 if ((!str1)||(!str2))
502 return str1;
503 len= strlen(str1)+strlen(str2)+1;
504 str1= _XkbTypedRealloc(str1,len,char);
505 if (str1)
506 strcat(str1,str2);
507 return str1;
510 static void
511 squeeze_spaces(char *p1)
513 char *p2;
514 for (p2 = p1; *p2; p2++) {
515 *p1 = *p2;
516 if (*p1 != ' ') p1++;
518 *p1 = '\0';
521 static Bool
522 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
525 bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec));
526 mdefs->model = defs->model;
527 mdefs->options = _XkbDupString(defs->options);
528 if (mdefs->options) squeeze_spaces(mdefs->options);
530 if (defs->layout) {
531 if (!strchr(defs->layout, ',')) {
532 mdefs->layout[0] = defs->layout;
533 } else {
534 char *p;
535 int i;
536 mdefs->layout[1] = _XkbDupString(defs->layout);
537 if (mdefs->layout[1] == NULL)
538 return False;
539 squeeze_spaces(mdefs->layout[1]);
540 p = mdefs->layout[1];
541 for (i = 2; i <= XkbNumKbdGroups; i++) {
542 if ((p = strchr(p, ','))) {
543 *p++ = '\0';
544 mdefs->layout[i] = p;
545 } else {
546 break;
549 if (p && (p = strchr(p, ',')))
550 *p = '\0';
554 if (defs->variant) {
555 if (!strchr(defs->variant, ',')) {
556 mdefs->variant[0] = defs->variant;
557 } else {
558 char *p;
559 int i;
560 mdefs->variant[1] = _XkbDupString(defs->variant);
561 if (mdefs->variant[1] == NULL)
562 return False;
563 squeeze_spaces(mdefs->variant[1]);
564 p = mdefs->variant[1];
565 for (i = 2; i <= XkbNumKbdGroups; i++) {
566 if ((p = strchr(p, ','))) {
567 *p++ = '\0';
568 mdefs->variant[i] = p;
569 } else {
570 break;
573 if (p && (p = strchr(p, ',')))
574 *p = '\0';
577 return True;
580 static void
581 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
583 if (defs->options) _XkbFree(defs->options);
584 if (defs->layout[1]) _XkbFree(defs->layout[1]);
585 if (defs->variant[1]) _XkbFree(defs->variant[1]);
588 static void
589 Apply(char *src, char **dst)
591 if (src) {
592 if (*src == '+' || *src == '!') {
593 *dst= _Concat(*dst, src);
594 } else {
595 if (*dst == NULL)
596 *dst= _XkbDupString(src);
601 static void
602 XkbRF_ApplyRule( XkbRF_RulePtr rule,
603 XkbComponentNamesPtr names)
605 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
607 Apply(rule->keycodes, &names->keycodes);
608 Apply(rule->symbols, &names->symbols);
609 Apply(rule->types, &names->types);
610 Apply(rule->compat, &names->compat);
611 Apply(rule->geometry, &names->geometry);
612 Apply(rule->keymap, &names->keymap);
615 static Bool
616 CheckGroup( XkbRF_RulesPtr rules,
617 char * group_name,
618 char * name)
620 int i;
621 char *p;
622 XkbRF_GroupPtr group;
624 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
625 if (! strcmp(group->name, group_name)) {
626 break;
629 if (i == rules->num_groups)
630 return False;
631 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
632 if (! strcmp(p, name)) {
633 return True;
636 return False;
639 static int
640 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
641 XkbRF_MultiDefsPtr mdefs,
642 XkbComponentNamesPtr names,
643 XkbRF_RulesPtr rules)
645 Bool pending = False;
647 if (rule->model != NULL) {
648 if(mdefs->model == NULL)
649 return 0;
650 if (strcmp(rule->model, "*") == 0) {
651 pending = True;
652 } else {
653 if (rule->model[0] == '$') {
654 if (!CheckGroup(rules, rule->model, mdefs->model))
655 return 0;
656 } else {
657 if (strcmp(rule->model, mdefs->model) != 0)
658 return 0;
662 if (rule->option != NULL) {
663 if (mdefs->options == NULL)
664 return 0;
665 if ((!MatchOneOf(rule->option,mdefs->options)))
666 return 0;
669 if (rule->layout != NULL) {
670 if(mdefs->layout[rule->layout_num] == NULL ||
671 *mdefs->layout[rule->layout_num] == '\0')
672 return 0;
673 if (strcmp(rule->layout, "*") == 0) {
674 pending = True;
675 } else {
676 if (rule->layout[0] == '$') {
677 if (!CheckGroup(rules, rule->layout,
678 mdefs->layout[rule->layout_num]))
679 return 0;
680 } else {
681 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
682 return 0;
686 if (rule->variant != NULL) {
687 if (mdefs->variant[rule->variant_num] == NULL ||
688 *mdefs->variant[rule->variant_num] == '\0')
689 return 0;
690 if (strcmp(rule->variant, "*") == 0) {
691 pending = True;
692 } else {
693 if (rule->variant[0] == '$') {
694 if (!CheckGroup(rules, rule->variant,
695 mdefs->variant[rule->variant_num]))
696 return 0;
697 } else {
698 if (strcmp(rule->variant,
699 mdefs->variant[rule->variant_num]) != 0)
700 return 0;
704 if (pending) {
705 rule->flags|= XkbRF_PendingMatch;
706 return rule->number;
708 /* exact match, apply it now */
709 XkbRF_ApplyRule(rule,names);
710 return rule->number;
713 static void
714 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
716 register int i;
717 XkbRF_RulePtr rule;
719 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
720 rule->flags&= ~XkbRF_PendingMatch;
724 static void
725 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names)
727 int i;
728 XkbRF_RulePtr rule;
730 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
731 if ((rule->flags&XkbRF_PendingMatch)==0)
732 continue;
733 XkbRF_ApplyRule(rule,names);
737 static void
738 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
739 XkbRF_MultiDefsPtr mdefs,
740 XkbComponentNamesPtr names,
741 int flags)
743 int i;
744 XkbRF_RulePtr rule;
745 int skip;
747 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
748 if ((rule->flags & flags) != flags)
749 continue;
750 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
751 if (skip && !(flags & XkbRF_Option)) {
752 for ( ;(i < rules->num_rules) && (rule->number == skip);
753 rule++, i++);
754 rule--; i--;
759 /***====================================================================***/
761 static char *
762 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
764 char *str, *outstr, *orig, *var;
765 int len, ndx;
767 orig= name;
768 str= index(name,'%');
769 if (str==NULL)
770 return name;
771 len= strlen(name);
772 while (str!=NULL) {
773 char pfx= str[1];
774 int extra_len= 0;
775 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
776 extra_len= 1;
777 str++;
779 else if (pfx=='(') {
780 extra_len= 2;
781 str++;
783 var = str + 1;
784 str = get_index(var + 1, &ndx);
785 if (ndx == -1) {
786 str = index(str,'%');
787 continue;
789 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
790 len+= strlen(mdefs->layout[ndx])+extra_len;
791 else if ((*var=='m')&&mdefs->model)
792 len+= strlen(mdefs->model)+extra_len;
793 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
794 len+= strlen(mdefs->variant[ndx])+extra_len;
795 if ((pfx=='(')&&(*str==')')) {
796 str++;
798 str= index(&str[0],'%');
800 name= (char *)_XkbAlloc(len+1);
801 str= orig;
802 outstr= name;
803 while (*str!='\0') {
804 if (str[0]=='%') {
805 char pfx,sfx;
806 str++;
807 pfx= str[0];
808 sfx= '\0';
809 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
810 str++;
812 else if (pfx=='(') {
813 sfx= ')';
814 str++;
816 else pfx= '\0';
818 var = str;
819 str = get_index(var + 1, &ndx);
820 if (ndx == -1) {
821 continue;
823 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
824 if (pfx) *outstr++= pfx;
825 strcpy(outstr,mdefs->layout[ndx]);
826 outstr+= strlen(mdefs->layout[ndx]);
827 if (sfx) *outstr++= sfx;
829 else if ((*var=='m')&&(mdefs->model)) {
830 if (pfx) *outstr++= pfx;
831 strcpy(outstr,mdefs->model);
832 outstr+= strlen(mdefs->model);
833 if (sfx) *outstr++= sfx;
835 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
836 if (pfx) *outstr++= pfx;
837 strcpy(outstr,mdefs->variant[ndx]);
838 outstr+= strlen(mdefs->variant[ndx]);
839 if (sfx) *outstr++= sfx;
841 if ((pfx=='(')&&(*str==')'))
842 str++;
844 else {
845 *outstr++= *str++;
848 *outstr++= '\0';
849 if (orig!=name)
850 _XkbFree(orig);
851 return name;
854 /***====================================================================***/
856 Bool
857 XkbRF_GetComponents( XkbRF_RulesPtr rules,
858 XkbRF_VarDefsPtr defs,
859 XkbComponentNamesPtr names)
861 XkbRF_MultiDefsRec mdefs;
863 MakeMultiDefs(&mdefs, defs);
865 bzero((char *)names,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);
873 if (names->keycodes)
874 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
875 if (names->symbols)
876 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
877 if (names->types)
878 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
879 if (names->compat)
880 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
881 if (names->geometry)
882 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
883 if (names->keymap)
884 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
886 FreeMultiDefs(&mdefs);
887 return (names->keycodes && names->symbols && names->types &&
888 names->compat && names->geometry ) || names->keymap;
891 XkbRF_RulePtr
892 XkbRF_AddRule(XkbRF_RulesPtr rules)
894 if (rules->sz_rules<1) {
895 rules->sz_rules= 16;
896 rules->num_rules= 0;
897 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
899 else if (rules->num_rules>=rules->sz_rules) {
900 rules->sz_rules*= 2;
901 rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
902 XkbRF_RuleRec);
904 if (!rules->rules) {
905 rules->sz_rules= rules->num_rules= 0;
906 #ifdef DEBUG
907 fprintf(stderr,"Allocation failure in XkbRF_AddRule\n");
908 #endif
909 return NULL;
911 bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec));
912 return &rules->rules[rules->num_rules++];
915 XkbRF_GroupPtr
916 XkbRF_AddGroup(XkbRF_RulesPtr rules)
918 if (rules->sz_groups<1) {
919 rules->sz_groups= 16;
920 rules->num_groups= 0;
921 rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
923 else if (rules->num_groups >= rules->sz_groups) {
924 rules->sz_groups *= 2;
925 rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups,
926 XkbRF_GroupRec);
928 if (!rules->groups) {
929 rules->sz_groups= rules->num_groups= 0;
930 return NULL;
933 bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec));
934 return &rules->groups[rules->num_groups++];
937 Bool
938 XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
940 InputLine line;
941 RemapSpec remap;
942 XkbRF_RuleRec trule,*rule;
943 XkbRF_GroupRec tgroup,*group;
945 if (!(rules && file))
946 return False;
947 bzero((char *)&remap,sizeof(RemapSpec));
948 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
949 InitInputLine(&line);
950 while (GetInputLine(file,&line,True)) {
951 if (CheckLine(&line,&remap,&trule,&tgroup)) {
952 if (tgroup.number) {
953 if ((group= XkbRF_AddGroup(rules))!=NULL) {
954 *group= tgroup;
955 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
957 } else {
958 if ((rule= XkbRF_AddRule(rules))!=NULL) {
959 *rule= trule;
960 bzero((char *)&trule,sizeof(XkbRF_RuleRec));
964 line.num_line= 0;
966 FreeInputLine(&line);
967 return True;
970 Bool
971 XkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules)
973 FILE * file;
974 char buf[PATH_MAX];
975 Bool ok;
977 if ((!base)||(!rules))
978 return False;
979 if (locale) {
980 if (strlen(base)+strlen(locale)+2 > PATH_MAX)
981 return False;
982 sprintf(buf,"%s-%s", base, locale);
984 else {
985 if (strlen(base)+1 > PATH_MAX)
986 return False;
987 strcpy(buf,base);
990 file= fopen(buf, "r");
991 if ((!file)&&(locale)) { /* fallback if locale was specified */
992 strcpy(buf,base);
993 file= fopen(buf, "r");
995 if (!file)
996 return False;
997 ok= XkbRF_LoadRules(file,rules);
998 fclose(file);
999 return ok;
1002 /***====================================================================***/
1004 #define HEAD_NONE 0
1005 #define HEAD_MODEL 1
1006 #define HEAD_LAYOUT 2
1007 #define HEAD_VARIANT 3
1008 #define HEAD_OPTION 4
1009 #define HEAD_EXTRA 5
1011 XkbRF_VarDescPtr
1012 XkbRF_AddVarDesc(XkbRF_DescribeVarsPtr vars)
1014 if (vars->sz_desc<1) {
1015 vars->sz_desc= 16;
1016 vars->num_desc= 0;
1017 vars->desc= _XkbTypedCalloc(vars->sz_desc,XkbRF_VarDescRec);
1019 else if (vars->num_desc>=vars->sz_desc) {
1020 vars->sz_desc*= 2;
1021 vars->desc= _XkbTypedRealloc(vars->desc,vars->sz_desc,XkbRF_VarDescRec);
1023 if (!vars->desc) {
1024 vars->sz_desc= vars->num_desc= 0;
1025 PR_DEBUG("Allocation failure in XkbRF_AddVarDesc\n");
1026 return NULL;
1028 vars->desc[vars->num_desc].name= NULL;
1029 vars->desc[vars->num_desc].desc= NULL;
1030 return &vars->desc[vars->num_desc++];
1033 XkbRF_VarDescPtr
1034 XkbRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars,XkbRF_VarDescPtr from)
1036 XkbRF_VarDescPtr nd;
1038 if ((nd=XkbRF_AddVarDesc(vars))!=NULL) {
1039 nd->name= _XkbDupString(from->name);
1040 nd->desc= _XkbDupString(from->desc);
1042 return nd;
1045 XkbRF_DescribeVarsPtr
1046 XkbRF_AddVarToDescribe(XkbRF_RulesPtr rules,char *name)
1048 if (rules->sz_extra<1) {
1049 rules->num_extra= 0;
1050 rules->sz_extra= 1;
1051 rules->extra_names= _XkbTypedCalloc(rules->sz_extra,char *);
1052 rules->extra= _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec);
1054 else if (rules->num_extra>=rules->sz_extra) {
1055 rules->sz_extra*= 2;
1056 rules->extra_names= _XkbTypedRealloc(rules->extra_names,rules->sz_extra,
1057 char *);
1058 rules->extra=_XkbTypedRealloc(rules->extra, rules->sz_extra,
1059 XkbRF_DescribeVarsRec);
1061 if ((!rules->extra_names)||(!rules->extra)) {
1062 PR_DEBUG("allocation error in extra parts\n");
1063 rules->sz_extra= rules->num_extra= 0;
1064 rules->extra_names= NULL;
1065 rules->extra= NULL;
1066 return NULL;
1068 rules->extra_names[rules->num_extra]= _XkbDupString(name);
1069 bzero(&rules->extra[rules->num_extra],sizeof(XkbRF_DescribeVarsRec));
1070 return &rules->extra[rules->num_extra++];
1073 Bool
1074 XkbRF_LoadDescriptions(FILE *file,XkbRF_RulesPtr rules)
1076 InputLine line;
1077 XkbRF_VarDescRec tmp;
1078 char *tok;
1079 int len,headingtype,extra_ndx = 0;
1081 bzero((char *)&tmp, sizeof(XkbRF_VarDescRec));
1082 headingtype = HEAD_NONE;
1083 InitInputLine(&line);
1084 for ( ; GetInputLine(file,&line,False); line.num_line= 0) {
1085 if (line.line[0]=='!') {
1086 tok = strtok(&(line.line[1]), " \t");
1087 if (strcasecmp(tok,"model") == 0)
1088 headingtype = HEAD_MODEL;
1089 else if (strcasecmp(tok,"layout") == 0)
1090 headingtype = HEAD_LAYOUT;
1091 else if (strcasecmp(tok,"variant") == 0)
1092 headingtype = HEAD_VARIANT;
1093 else if (strcasecmp(tok,"option") == 0)
1094 headingtype = HEAD_OPTION;
1095 else {
1096 int i;
1097 headingtype = HEAD_EXTRA;
1098 extra_ndx= -1;
1099 for (i=0;(i<rules->num_extra)&&(extra_ndx<0);i++) {
1100 if (!strcasecmp(tok,rules->extra_names[i]))
1101 extra_ndx= i;
1103 if (extra_ndx<0) {
1104 XkbRF_DescribeVarsPtr var;
1105 PR_DEBUG1("Extra heading \"%s\" encountered\n",tok);
1106 var= XkbRF_AddVarToDescribe(rules,tok);
1107 if (var)
1108 extra_ndx= var-rules->extra;
1109 else headingtype= HEAD_NONE;
1112 continue;
1115 if (headingtype == HEAD_NONE) {
1116 PR_DEBUG("Must have a heading before first line of data\n");
1117 PR_DEBUG("Illegal line of data ignored\n");
1118 continue;
1121 len = strlen(line.line);
1122 if ((tmp.name= strtok(line.line, " \t")) == NULL) {
1123 PR_DEBUG("Huh? No token on line\n");
1124 PR_DEBUG("Illegal line of data ignored\n");
1125 continue;
1127 if (strlen(tmp.name) == len) {
1128 PR_DEBUG("No description found\n");
1129 PR_DEBUG("Illegal line of data ignored\n");
1130 continue;
1133 tok = line.line + strlen(tmp.name) + 1;
1134 while ((*tok!='\n')&&isspace(*tok))
1135 tok++;
1136 if (*tok == '\0') {
1137 PR_DEBUG("No description found\n");
1138 PR_DEBUG("Illegal line of data ignored\n");
1139 continue;
1141 tmp.desc= tok;
1142 switch (headingtype) {
1143 case HEAD_MODEL:
1144 XkbRF_AddVarDescCopy(&rules->models,&tmp);
1145 break;
1146 case HEAD_LAYOUT:
1147 XkbRF_AddVarDescCopy(&rules->layouts,&tmp);
1148 break;
1149 case HEAD_VARIANT:
1150 XkbRF_AddVarDescCopy(&rules->variants,&tmp);
1151 break;
1152 case HEAD_OPTION:
1153 XkbRF_AddVarDescCopy(&rules->options,&tmp);
1154 break;
1155 case HEAD_EXTRA:
1156 XkbRF_AddVarDescCopy(&rules->extra[extra_ndx],&tmp);
1157 break;
1160 FreeInputLine(&line);
1161 if ((rules->models.num_desc==0) && (rules->layouts.num_desc==0) &&
1162 (rules->variants.num_desc==0) && (rules->options.num_desc==0) &&
1163 (rules->num_extra==0)) {
1164 return False;
1166 return True;
1169 Bool
1170 XkbRF_LoadDescriptionsByName(char *base,char *locale,XkbRF_RulesPtr rules)
1172 FILE * file;
1173 char buf[PATH_MAX];
1174 Bool ok;
1176 if ((!base)||(!rules))
1177 return False;
1178 if (locale) {
1179 if (strlen(base)+strlen(locale)+6 > PATH_MAX)
1180 return False;
1181 sprintf(buf,"%s-%s.lst", base, locale);
1183 else {
1184 if (strlen(base)+5 > PATH_MAX)
1185 return False;
1186 sprintf(buf,"%s.lst", base);
1189 file= fopen(buf, "r");
1190 if ((!file)&&(locale)) { /* fallback if locale was specified */
1191 sprintf(buf,"%s.lst", base);
1193 file= fopen(buf, "r");
1195 if (!file)
1196 return False;
1197 ok= XkbRF_LoadDescriptions(file,rules);
1198 fclose(file);
1199 return ok;
1202 /***====================================================================***/
1204 XkbRF_RulesPtr
1205 XkbRF_Load(char *base,char *locale,Bool wantDesc,Bool wantRules)
1207 XkbRF_RulesPtr rules;
1209 if ((!base)||((!wantDesc)&&(!wantRules)))
1210 return NULL;
1211 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
1212 return NULL;
1213 if (wantDesc&&(!XkbRF_LoadDescriptionsByName(base,locale,rules))) {
1214 XkbRF_Free(rules,True);
1215 return NULL;
1217 if (wantRules&&(!XkbRF_LoadRulesByName(base,locale,rules))) {
1218 XkbRF_Free(rules,True);
1219 return NULL;
1221 return rules;
1224 XkbRF_RulesPtr
1225 XkbRF_Create(int szRules,int szExtra)
1227 XkbRF_RulesPtr rules;
1229 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
1230 return NULL;
1231 if (szRules>0) {
1232 rules->sz_rules= szRules;
1233 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
1234 if (!rules->rules) {
1235 _XkbFree(rules);
1236 return NULL;
1239 if (szExtra>0) {
1240 rules->sz_extra= szExtra;
1241 rules->extra= _XkbTypedCalloc(rules->sz_extra,XkbRF_DescribeVarsRec);
1242 if (!rules->extra) {
1243 if (rules->rules)
1244 _XkbFree(rules->rules);
1245 _XkbFree(rules);
1246 return NULL;
1249 return rules;
1252 /***====================================================================***/
1254 static void
1255 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
1257 register int i;
1259 for (i=0;i<var->num_desc;i++) {
1260 if (var->desc[i].name)
1261 _XkbFree(var->desc[i].name);
1262 if (var->desc[i].desc)
1263 _XkbFree(var->desc[i].desc);
1264 var->desc[i].name= var->desc[i].desc= NULL;
1266 if (var->desc)
1267 _XkbFree(var->desc);
1268 var->desc= NULL;
1269 return;
1272 void
1273 XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
1275 int i;
1276 XkbRF_RulePtr rule;
1277 XkbRF_GroupPtr group;
1279 if (!rules)
1280 return;
1281 XkbRF_ClearVarDescriptions(&rules->models);
1282 XkbRF_ClearVarDescriptions(&rules->layouts);
1283 XkbRF_ClearVarDescriptions(&rules->variants);
1284 XkbRF_ClearVarDescriptions(&rules->options);
1285 if (rules->extra) {
1286 for (i = 0; i < rules->num_extra; i++) {
1287 XkbRF_ClearVarDescriptions(&rules->extra[i]);
1289 _XkbFree(rules->extra);
1290 rules->num_extra= rules->sz_extra= 0;
1291 rules->extra= NULL;
1293 if (rules->rules) {
1294 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
1295 if (rule->model) _XkbFree(rule->model);
1296 if (rule->layout) _XkbFree(rule->layout);
1297 if (rule->variant) _XkbFree(rule->variant);
1298 if (rule->option) _XkbFree(rule->option);
1299 if (rule->keycodes) _XkbFree(rule->keycodes);
1300 if (rule->symbols) _XkbFree(rule->symbols);
1301 if (rule->types) _XkbFree(rule->types);
1302 if (rule->compat) _XkbFree(rule->compat);
1303 if (rule->geometry) _XkbFree(rule->geometry);
1304 if (rule->keymap) _XkbFree(rule->keymap);
1305 bzero((char *)rule,sizeof(XkbRF_RuleRec));
1307 _XkbFree(rules->rules);
1308 rules->num_rules= rules->sz_rules= 0;
1309 rules->rules= NULL;
1312 if (rules->groups) {
1313 for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) {
1314 if (group->name) _XkbFree(group->name);
1315 if (group->words) _XkbFree(group->words);
1317 _XkbFree(rules->groups);
1318 rules->num_groups= 0;
1319 rules->groups= NULL;
1321 if (freeRules)
1322 _XkbFree(rules);
1323 return;