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 ********************************************************/
31 #include "xkbcommon/xkbcommon.h"
32 #include "XKBcommonint.h"
34 #ifdef HAVE_DIX_CONFIG_H
35 #include <dix-config.h>
36 #elif defined(HAVE_CONFIG_H)
44 #define X_INCLUDE_STRING_H
45 #define XOS_USE_NO_LOCKING
46 #include <X11/Xos_r.h>
48 #include <X11/Xproto.h>
51 #include <X11/Xfuncs.h>
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)
59 #define PR_DEBUG1(s,a)
60 #define PR_DEBUG2(s,a,b)
63 /***====================================================================***/
65 #define DFLT_LINE_SIZE 128
71 char buf[DFLT_LINE_SIZE];
76 InitInputLine(InputLine *line)
80 line->sz_line= DFLT_LINE_SIZE;
81 line->line= line->buf;
86 FreeInputLine(InputLine *line)
88 if (line->line!=line->buf)
92 line->sz_line= DFLT_LINE_SIZE;
93 line->line= line->buf;
98 InputLineAddChar(InputLine *line,int ch)
100 if (line->num_line>=line->sz_line) {
101 if (line->line==line->buf) {
102 line->line= (char *)malloc(line->sz_line*2);
103 memcpy(line->line,line->buf,line->sz_line);
106 line->line=(char *)realloc((char *)line->line,line->sz_line*2);
110 line->line[line->num_line++]= 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))
119 GetInputLine(FILE *file,InputLine *line,Bool checkbang)
122 Bool endOfFile,spacePending,slashPending,inComment;
125 while ((!endOfFile)&&(line->num_line==0)) {
126 spacePending= slashPending= inComment= False;
127 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
129 if ((ch=getc(file))==EOF)
149 else if (slashPending) {
158 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
163 if ((ch!='\n')&&(line->num_line>0))
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");
186 /* else line->num_line++;*/
188 if ((line->num_line==0)&&(endOfFile))
194 /***====================================================================***/
208 #define PART_MASK 0x000F
209 #define COMPONENT_MASK 0x03F0
211 static char * cname[MAX_WORDS] = {
212 "model", "layout", "variant", "option",
213 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
216 typedef struct _RemapSpec {
225 typedef struct _FileSpec {
226 char * name[MAX_WORDS];
227 struct _FileSpec * pending;
232 char * layout[XkbNumKbdGroups+1];
233 char * variant[XkbNumKbdGroups+1];
235 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
237 #define NDX_BUFF_SIZE 4
239 /***====================================================================***/
242 get_index(char *str, int *ndx)
244 char ndx_buf[NDX_BUFF_SIZE];
252 end = strchr(str, ']');
257 if ( (end - str) >= NDX_BUFF_SIZE) {
261 strncpy(ndx_buf, str, end - str);
262 ndx_buf[end - str] = '\0';
263 *ndx = atoi(ndx_buf);
268 SetUpRemap(InputLine *line,RemapSpec *remap)
271 unsigned present, l_ndx_present, v_ndx_present;
274 _Xstrtokparams strtok_buf;
280 l_ndx_present = v_ndx_present = present= 0;
283 bzero((char *)remap,sizeof(RemapSpec));
285 while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
290 if (strcmp(tok,"=")==0)
292 for (i=0;i<MAX_WORDS;i++) {
293 len = strlen(cname[i]);
294 if (strncmp(cname[i],tok,len)==0) {
295 if(strlen(tok) > len) {
296 char *end = get_index(tok+len, &ndx);
297 if ((i != LAYOUT && i != VARIANT) ||
298 *end != '\0' || ndx == -1)
300 if (ndx < 1 || ndx > XkbNumKbdGroups) {
301 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
302 PR_DEBUG1("Index must be in range 1..%d\n",
312 if (present&(1<<i)) {
313 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
314 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
315 PR_DEBUG1("Component \"%s\" listed twice\n",tok);
316 PR_DEBUG("Second definition ignored\n");
322 l_ndx_present |= 1 << ndx;
324 v_ndx_present |= 1 << ndx;
325 remap->remap[remap->num_remap].word= i;
326 remap->remap[remap->num_remap++].index= ndx;
332 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
336 if ((present&PART_MASK)==0) {
338 unsigned mask= PART_MASK;
339 fprintf(stderr,"Mapping needs at least one of ");
340 for (i=0; (i<MAX_WORDS); i++) {
343 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
344 else fprintf(stderr,"or \"%s\"\n",cname[i]);
347 fprintf(stderr,"Illegal mapping ignored\n");
352 if ((present&COMPONENT_MASK)==0) {
353 PR_DEBUG("Mapping needs at least one component\n");
354 PR_DEBUG("Illegal mapping ignored\n");
358 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
359 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
360 PR_DEBUG("Keymap cannot appear with other components\n");
361 PR_DEBUG("Illegal mapping ignored\n");
370 MatchOneOf(char *wanted,char *vals_defined)
373 int want_len= strlen(wanted);
375 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
377 next= strchr(str,',');
385 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
391 /***====================================================================***/
394 CheckLine( InputLine * line,
397 XkbRF_GroupPtr group)
400 register int nread, i;
402 _Xstrtokparams strtok_buf;
405 if (line->line[0]=='!') {
406 if (line->line[1] == '$' ||
407 (line->line[1] == ' ' && line->line[2] == '$')) {
408 char *gname = strchr(line->line, '$');
409 char *words = strchr(gname, ' ');
413 for (; *words; words++) {
414 if (*words != '=' && *words != ' ')
419 group->name = _XkbDupString(gname);
420 group->words = _XkbDupString(words);
421 for (i = 1, words = group->words; *words; words++) {
422 if ( *words == ' ') {
430 SetUpRemap(line,remap);
435 if (remap->num_remap==0) {
436 PR_DEBUG("Must have a mapping before first line of data\n");
437 PR_DEBUG("Illegal line of data ignored\n");
440 bzero((char *)&tmp,sizeof(FileSpec));
442 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
444 if (strcmp(tok,"=")==0) {
448 if (nread>remap->num_remap) {
449 PR_DEBUG("Too many words on a line\n");
450 PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
453 tmp.name[remap->remap[nread].word]= tok;
454 if (*tok == '+' || *tok == '|')
457 if (nread<remap->num_remap) {
458 PR_DEBUG1("Too few words on a line: %s\n", line->line);
459 PR_DEBUG("line ignored\n");
464 rule->number = remap->number;
465 if (tmp.name[OPTION])
466 rule->flags|= XkbRF_Option;
468 rule->flags|= XkbRF_Append;
470 rule->flags|= XkbRF_Normal;
471 rule->model= _XkbDupString(tmp.name[MODEL]);
472 rule->layout= _XkbDupString(tmp.name[LAYOUT]);
473 rule->variant= _XkbDupString(tmp.name[VARIANT]);
474 rule->option= _XkbDupString(tmp.name[OPTION]);
476 rule->keycodes= _XkbDupString(tmp.name[KEYCODES]);
477 rule->symbols= _XkbDupString(tmp.name[SYMBOLS]);
478 rule->types= _XkbDupString(tmp.name[TYPES]);
479 rule->compat= _XkbDupString(tmp.name[COMPAT]);
480 rule->geometry= _XkbDupString(tmp.name[GEOMETRY]);
481 rule->keymap= _XkbDupString(tmp.name[KEYMAP]);
483 rule->layout_num = rule->variant_num = 0;
484 for (i = 0; i < nread; i++) {
485 if (remap->remap[i].index) {
486 if (remap->remap[i].word == LAYOUT)
487 rule->layout_num = remap->remap[i].index;
488 if (remap->remap[i].word == VARIANT)
489 rule->variant_num = remap->remap[i].index;
496 _Concat(char *str1,char *str2)
500 if ((!str1)||(!str2))
502 len= strlen(str1)+strlen(str2)+1;
503 str1= _XkbTypedRealloc(str1,len,char);
510 squeeze_spaces(char *p1)
513 for (p2 = p1; *p2; p2++) {
515 if (*p1 != ' ') p1++;
521 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
523 bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec));
524 mdefs->model = defs->model;
525 mdefs->options = _XkbDupString(defs->options);
526 if (mdefs->options) squeeze_spaces(mdefs->options);
529 if (!strchr(defs->layout, ',')) {
530 mdefs->layout[0] = defs->layout;
534 mdefs->layout[1] = _XkbDupString(defs->layout);
535 if (mdefs->layout[1] == NULL)
537 squeeze_spaces(mdefs->layout[1]);
538 p = mdefs->layout[1];
539 for (i = 2; i <= XkbNumKbdGroups; i++) {
540 if ((p = strchr(p, ','))) {
542 mdefs->layout[i] = p;
547 if (p && (p = strchr(p, ',')))
553 if (!strchr(defs->variant, ',')) {
554 mdefs->variant[0] = defs->variant;
558 mdefs->variant[1] = _XkbDupString(defs->variant);
559 if (mdefs->variant[1] == NULL)
561 squeeze_spaces(mdefs->variant[1]);
562 p = mdefs->variant[1];
563 for (i = 2; i <= XkbNumKbdGroups; i++) {
564 if ((p = strchr(p, ','))) {
566 mdefs->variant[i] = p;
571 if (p && (p = strchr(p, ',')))
579 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
581 if (defs->options) free(defs->options);
582 if (defs->layout[1]) free(defs->layout[1]);
583 if (defs->variant[1]) free(defs->variant[1]);
587 Apply(char *src, char **dst)
590 if (*src == '+' || *src == '!') {
591 *dst= _Concat(*dst, src);
594 *dst= _XkbDupString(src);
600 XkbRF_ApplyRule( XkbRF_RulePtr rule,
601 struct xkb_component_names * names)
603 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
605 Apply(rule->keycodes, &names->keycodes);
606 Apply(rule->symbols, &names->symbols);
607 Apply(rule->types, &names->types);
608 Apply(rule->compat, &names->compat);
609 Apply(rule->geometry, &names->geometry);
610 Apply(rule->keymap, &names->keymap);
614 CheckGroup( XkbRF_RulesPtr rules,
620 XkbRF_GroupPtr group;
622 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
623 if (! strcmp(group->name, group_name)) {
627 if (i == rules->num_groups)
629 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
630 if (! strcmp(p, name)) {
638 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
639 XkbRF_MultiDefsPtr mdefs,
640 struct xkb_component_names * names,
641 XkbRF_RulesPtr rules)
643 Bool pending = False;
645 if (rule->model != NULL) {
646 if(mdefs->model == NULL)
648 if (strcmp(rule->model, "*") == 0) {
651 if (rule->model[0] == '$') {
652 if (!CheckGroup(rules, rule->model, mdefs->model))
655 if (strcmp(rule->model, mdefs->model) != 0)
660 if (rule->option != NULL) {
661 if (mdefs->options == NULL)
663 if ((!MatchOneOf(rule->option,mdefs->options)))
667 if (rule->layout != NULL) {
668 if(mdefs->layout[rule->layout_num] == NULL ||
669 *mdefs->layout[rule->layout_num] == '\0')
671 if (strcmp(rule->layout, "*") == 0) {
674 if (rule->layout[0] == '$') {
675 if (!CheckGroup(rules, rule->layout,
676 mdefs->layout[rule->layout_num]))
679 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
684 if (rule->variant != NULL) {
685 if (mdefs->variant[rule->variant_num] == NULL ||
686 *mdefs->variant[rule->variant_num] == '\0')
688 if (strcmp(rule->variant, "*") == 0) {
691 if (rule->variant[0] == '$') {
692 if (!CheckGroup(rules, rule->variant,
693 mdefs->variant[rule->variant_num]))
696 if (strcmp(rule->variant,
697 mdefs->variant[rule->variant_num]) != 0)
703 rule->flags|= XkbRF_PendingMatch;
706 /* exact match, apply it now */
707 XkbRF_ApplyRule(rule,names);
712 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
717 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
718 rule->flags&= ~XkbRF_PendingMatch;
723 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,struct xkb_component_names * names)
728 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
729 if ((rule->flags&XkbRF_PendingMatch)==0)
731 XkbRF_ApplyRule(rule,names);
736 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
737 XkbRF_MultiDefsPtr mdefs,
738 struct xkb_component_names * names,
745 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
746 if ((rule->flags & flags) != flags)
748 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
749 if (skip && !(flags & XkbRF_Option)) {
750 for ( ;(i < rules->num_rules) && (rule->number == skip);
757 /***====================================================================***/
760 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
762 char *str, *outstr, *orig, *var;
766 str= index(name,'%');
773 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
782 str = get_index(var + 1, &ndx);
784 str = index(str,'%');
787 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
788 len+= strlen(mdefs->layout[ndx])+extra_len;
789 else if ((*var=='m')&&mdefs->model)
790 len+= strlen(mdefs->model)+extra_len;
791 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
792 len+= strlen(mdefs->variant[ndx])+extra_len;
793 if ((pfx=='(')&&(*str==')')) {
796 str= index(&str[0],'%');
798 name= (char *)malloc(len+1);
807 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
817 str = get_index(var + 1, &ndx);
821 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
822 if (pfx) *outstr++= pfx;
823 strcpy(outstr,mdefs->layout[ndx]);
824 outstr+= strlen(mdefs->layout[ndx]);
825 if (sfx) *outstr++= sfx;
827 else if ((*var=='m')&&(mdefs->model)) {
828 if (pfx) *outstr++= pfx;
829 strcpy(outstr,mdefs->model);
830 outstr+= strlen(mdefs->model);
831 if (sfx) *outstr++= sfx;
833 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
834 if (pfx) *outstr++= pfx;
835 strcpy(outstr,mdefs->variant[ndx]);
836 outstr+= strlen(mdefs->variant[ndx]);
837 if (sfx) *outstr++= sfx;
839 if ((pfx=='(')&&(*str==')'))
852 /***====================================================================***/
855 XkbcRF_GetComponents( XkbRF_RulesPtr rules,
856 XkbRF_VarDefsPtr defs,
857 struct xkb_component_names * names)
859 XkbRF_MultiDefsRec mdefs;
861 MakeMultiDefs(&mdefs, defs);
863 bzero((char *)names,sizeof(struct xkb_component_names));
864 XkbRF_ClearPartialMatches(rules);
865 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
866 XkbRF_ApplyPartialMatches(rules, names);
867 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
868 XkbRF_ApplyPartialMatches(rules, names);
869 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
870 XkbRF_ApplyPartialMatches(rules, names);
873 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
875 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
877 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
879 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
881 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
883 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
885 FreeMultiDefs(&mdefs);
886 return (names->keycodes && names->symbols && names->types &&
887 names->compat && names->geometry ) || names->keymap;
891 XkbcRF_AddRule(XkbRF_RulesPtr rules)
893 if (rules->sz_rules<1) {
896 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
898 else if (rules->num_rules>=rules->sz_rules) {
900 rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
904 rules->sz_rules= rules->num_rules= 0;
906 fprintf(stderr,"Allocation failure in XkbcRF_AddRule\n");
910 bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec));
911 return &rules->rules[rules->num_rules++];
914 static XkbRF_GroupPtr
915 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
917 if (rules->sz_groups<1) {
918 rules->sz_groups= 16;
919 rules->num_groups= 0;
920 rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
922 else if (rules->num_groups >= rules->sz_groups) {
923 rules->sz_groups *= 2;
924 rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups,
927 if (!rules->groups) {
928 rules->sz_groups= rules->num_groups= 0;
932 bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec));
933 return &rules->groups[rules->num_groups++];
937 XkbcRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
941 XkbRF_RuleRec trule,*rule;
942 XkbRF_GroupRec tgroup,*group;
944 if (!(rules && file))
946 bzero((char *)&remap,sizeof(RemapSpec));
947 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
948 InitInputLine(&line);
949 while (GetInputLine(file,&line,True)) {
950 if (CheckLine(&line,&remap,&trule,&tgroup)) {
952 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
954 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
957 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
959 bzero((char *)&trule,sizeof(XkbRF_RuleRec));
965 FreeInputLine(&line);
970 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
974 for (i=0;i<var->num_desc;i++) {
975 if (var->desc[i].name)
976 free(var->desc[i].name);
977 if (var->desc[i].desc)
978 free(var->desc[i].desc);
979 var->desc[i].name= var->desc[i].desc= NULL;
988 XkbcRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
992 XkbRF_GroupPtr group;
996 XkbRF_ClearVarDescriptions(&rules->models);
997 XkbRF_ClearVarDescriptions(&rules->layouts);
998 XkbRF_ClearVarDescriptions(&rules->variants);
999 XkbRF_ClearVarDescriptions(&rules->options);
1001 for (i = 0; i < rules->num_extra; i++) {
1002 XkbRF_ClearVarDescriptions(&rules->extra[i]);
1005 rules->num_extra= rules->sz_extra= 0;
1009 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
1010 if (rule->model) free(rule->model);
1011 if (rule->layout) free(rule->layout);
1012 if (rule->variant) free(rule->variant);
1013 if (rule->option) free(rule->option);
1014 if (rule->keycodes) free(rule->keycodes);
1015 if (rule->symbols) free(rule->symbols);
1016 if (rule->types) free(rule->types);
1017 if (rule->compat) free(rule->compat);
1018 if (rule->geometry) free(rule->geometry);
1019 if (rule->keymap) free(rule->keymap);
1020 bzero((char *)rule,sizeof(XkbRF_RuleRec));
1023 rules->num_rules= rules->sz_rules= 0;
1027 if (rules->groups) {
1028 for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) {
1029 if (group->name) free(group->name);
1030 if (group->words) free(group->words);
1032 free(rules->groups);
1033 rules->num_groups= 0;
1034 rules->groups= NULL;