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");
187 /* else line->num_line++;*/
189 if ((line->num_line==0)&&(endOfFile))
195 /***====================================================================***/
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 {
226 typedef struct _FileSpec {
227 char * name[MAX_WORDS];
228 struct _FileSpec * pending;
233 char * layout[XkbNumKbdGroups+1];
234 char * variant[XkbNumKbdGroups+1];
236 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
238 #define NDX_BUFF_SIZE 4
240 /***====================================================================***/
243 get_index(char *str, int *ndx)
245 char ndx_buf[NDX_BUFF_SIZE];
253 end = strchr(str, ']');
258 if ( (end - str) >= NDX_BUFF_SIZE) {
262 strncpy(ndx_buf, str, end - str);
263 ndx_buf[end - str] = '\0';
264 *ndx = atoi(ndx_buf);
269 SetUpRemap(InputLine *line,RemapSpec *remap)
272 unsigned present, l_ndx_present, v_ndx_present;
275 _Xstrtokparams strtok_buf;
281 l_ndx_present = v_ndx_present = present= 0;
284 bzero((char *)remap,sizeof(RemapSpec));
286 while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
291 if (strcmp(tok,"=")==0)
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)
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",
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");
323 l_ndx_present |= 1 << ndx;
325 v_ndx_present |= 1 << ndx;
326 remap->remap[remap->num_remap].word= i;
327 remap->remap[remap->num_remap++].index= ndx;
333 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
337 if ((present&PART_MASK)==0) {
339 unsigned mask= PART_MASK;
340 fprintf(stderr,"Mapping needs at least one of ");
341 for (i=0; (i<MAX_WORDS); 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");
353 if ((present&COMPONENT_MASK)==0) {
354 PR_DEBUG("Mapping needs at least one component\n");
355 PR_DEBUG("Illegal mapping ignored\n");
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");
371 MatchOneOf(char *wanted,char *vals_defined)
374 int want_len= strlen(wanted);
376 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
378 next= strchr(str,',');
386 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
392 /***====================================================================***/
395 CheckLine( InputLine * line,
398 XkbRF_GroupPtr group)
401 register int nread, i;
403 _Xstrtokparams strtok_buf;
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, ' ');
414 for (; *words; words++) {
415 if (*words != '=' && *words != ' ')
420 group->name = _XkbDupString(gname);
421 group->words = _XkbDupString(words);
422 for (i = 1, words = group->words; *words; words++) {
423 if ( *words == ' ') {
431 SetUpRemap(line,remap);
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");
441 bzero((char *)&tmp,sizeof(FileSpec));
443 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
445 if (strcmp(tok,"=")==0) {
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);
454 tmp.name[remap->remap[nread].word]= tok;
455 if (*tok == '+' || *tok == '|')
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");
465 rule->number = remap->number;
466 if (tmp.name[OPTION])
467 rule->flags|= XkbRF_Option;
469 rule->flags|= XkbRF_Append;
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;
497 _Concat(char *str1,char *str2)
501 if ((!str1)||(!str2))
503 len= strlen(str1)+strlen(str2)+1;
504 str1= _XkbTypedRealloc(str1,len,char);
511 squeeze_spaces(char *p1)
514 for (p2 = p1; *p2; p2++) {
516 if (*p1 != ' ') p1++;
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);
531 if (!strchr(defs->layout, ',')) {
532 mdefs->layout[0] = defs->layout;
536 mdefs->layout[1] = _XkbDupString(defs->layout);
537 if (mdefs->layout[1] == NULL)
539 squeeze_spaces(mdefs->layout[1]);
540 p = mdefs->layout[1];
541 for (i = 2; i <= XkbNumKbdGroups; i++) {
542 if ((p = strchr(p, ','))) {
544 mdefs->layout[i] = p;
549 if (p && (p = strchr(p, ',')))
555 if (!strchr(defs->variant, ',')) {
556 mdefs->variant[0] = defs->variant;
560 mdefs->variant[1] = _XkbDupString(defs->variant);
561 if (mdefs->variant[1] == NULL)
563 squeeze_spaces(mdefs->variant[1]);
564 p = mdefs->variant[1];
565 for (i = 2; i <= XkbNumKbdGroups; i++) {
566 if ((p = strchr(p, ','))) {
568 mdefs->variant[i] = p;
573 if (p && (p = strchr(p, ',')))
581 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
583 if (defs->options) free(defs->options);
584 if (defs->layout[1]) free(defs->layout[1]);
585 if (defs->variant[1]) free(defs->variant[1]);
589 Apply(char *src, char **dst)
592 if (*src == '+' || *src == '!') {
593 *dst= _Concat(*dst, src);
596 *dst= _XkbDupString(src);
602 XkbRF_ApplyRule( XkbRF_RulePtr rule,
603 struct xkb_component_names * 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);
616 CheckGroup( XkbRF_RulesPtr rules,
622 XkbRF_GroupPtr group;
624 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
625 if (! strcmp(group->name, group_name)) {
629 if (i == rules->num_groups)
631 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
632 if (! strcmp(p, name)) {
640 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
641 XkbRF_MultiDefsPtr mdefs,
642 struct xkb_component_names * names,
643 XkbRF_RulesPtr rules)
645 Bool pending = False;
647 if (rule->model != NULL) {
648 if(mdefs->model == NULL)
650 if (strcmp(rule->model, "*") == 0) {
653 if (rule->model[0] == '$') {
654 if (!CheckGroup(rules, rule->model, mdefs->model))
657 if (strcmp(rule->model, mdefs->model) != 0)
662 if (rule->option != NULL) {
663 if (mdefs->options == NULL)
665 if ((!MatchOneOf(rule->option,mdefs->options)))
669 if (rule->layout != NULL) {
670 if(mdefs->layout[rule->layout_num] == NULL ||
671 *mdefs->layout[rule->layout_num] == '\0')
673 if (strcmp(rule->layout, "*") == 0) {
676 if (rule->layout[0] == '$') {
677 if (!CheckGroup(rules, rule->layout,
678 mdefs->layout[rule->layout_num]))
681 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
686 if (rule->variant != NULL) {
687 if (mdefs->variant[rule->variant_num] == NULL ||
688 *mdefs->variant[rule->variant_num] == '\0')
690 if (strcmp(rule->variant, "*") == 0) {
693 if (rule->variant[0] == '$') {
694 if (!CheckGroup(rules, rule->variant,
695 mdefs->variant[rule->variant_num]))
698 if (strcmp(rule->variant,
699 mdefs->variant[rule->variant_num]) != 0)
705 rule->flags|= XkbRF_PendingMatch;
708 /* exact match, apply it now */
709 XkbRF_ApplyRule(rule,names);
714 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
719 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
720 rule->flags&= ~XkbRF_PendingMatch;
725 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,struct xkb_component_names * names)
730 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
731 if ((rule->flags&XkbRF_PendingMatch)==0)
733 XkbRF_ApplyRule(rule,names);
738 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
739 XkbRF_MultiDefsPtr mdefs,
740 struct xkb_component_names * names,
747 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
748 if ((rule->flags & flags) != flags)
750 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
751 if (skip && !(flags & XkbRF_Option)) {
752 for ( ;(i < rules->num_rules) && (rule->number == skip);
759 /***====================================================================***/
762 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
764 char *str, *outstr, *orig, *var;
768 str= index(name,'%');
775 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
784 str = get_index(var + 1, &ndx);
786 str = index(str,'%');
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==')')) {
798 str= index(&str[0],'%');
800 name= (char *)malloc(len+1);
809 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
819 str = get_index(var + 1, &ndx);
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==')'))
854 /***====================================================================***/
857 XkbcRF_GetComponents( XkbRF_RulesPtr rules,
858 XkbRF_VarDefsPtr defs,
859 struct xkb_component_names * names)
861 XkbRF_MultiDefsRec mdefs;
863 MakeMultiDefs(&mdefs, defs);
865 bzero((char *)names,sizeof(struct xkb_component_names));
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);
875 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
877 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
879 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
881 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
883 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
885 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
887 FreeMultiDefs(&mdefs);
888 return (names->keycodes && names->symbols && names->types &&
889 names->compat && names->geometry ) || names->keymap;
893 XkbcRF_AddRule(XkbRF_RulesPtr rules)
895 if (rules->sz_rules<1) {
898 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
900 else if (rules->num_rules>=rules->sz_rules) {
902 rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
906 rules->sz_rules= rules->num_rules= 0;
908 fprintf(stderr,"Allocation failure in XkbcRF_AddRule\n");
912 bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec));
913 return &rules->rules[rules->num_rules++];
916 static XkbRF_GroupPtr
917 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
919 if (rules->sz_groups<1) {
920 rules->sz_groups= 16;
921 rules->num_groups= 0;
922 rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
924 else if (rules->num_groups >= rules->sz_groups) {
925 rules->sz_groups *= 2;
926 rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups,
929 if (!rules->groups) {
930 rules->sz_groups= rules->num_groups= 0;
934 bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec));
935 return &rules->groups[rules->num_groups++];
939 XkbcRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
943 XkbRF_RuleRec trule,*rule;
944 XkbRF_GroupRec tgroup,*group;
946 if (!(rules && file))
948 bzero((char *)&remap,sizeof(RemapSpec));
949 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
950 InitInputLine(&line);
951 while (GetInputLine(file,&line,True)) {
952 if (CheckLine(&line,&remap,&trule,&tgroup)) {
954 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
956 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
959 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
961 bzero((char *)&trule,sizeof(XkbRF_RuleRec));
967 FreeInputLine(&line);
972 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
976 for (i=0;i<var->num_desc;i++) {
977 if (var->desc[i].name)
978 free(var->desc[i].name);
979 if (var->desc[i].desc)
980 free(var->desc[i].desc);
981 var->desc[i].name= var->desc[i].desc= NULL;
990 XkbcRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
994 XkbRF_GroupPtr group;
998 XkbRF_ClearVarDescriptions(&rules->models);
999 XkbRF_ClearVarDescriptions(&rules->layouts);
1000 XkbRF_ClearVarDescriptions(&rules->variants);
1001 XkbRF_ClearVarDescriptions(&rules->options);
1003 for (i = 0; i < rules->num_extra; i++) {
1004 XkbRF_ClearVarDescriptions(&rules->extra[i]);
1007 rules->num_extra= rules->sz_extra= 0;
1011 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
1012 if (rule->model) free(rule->model);
1013 if (rule->layout) free(rule->layout);
1014 if (rule->variant) free(rule->variant);
1015 if (rule->option) free(rule->option);
1016 if (rule->keycodes) free(rule->keycodes);
1017 if (rule->symbols) free(rule->symbols);
1018 if (rule->types) free(rule->types);
1019 if (rule->compat) free(rule->compat);
1020 if (rule->geometry) free(rule->geometry);
1021 if (rule->keymap) free(rule->keymap);
1022 bzero((char *)rule,sizeof(XkbRF_RuleRec));
1025 rules->num_rules= rules->sz_rules= 0;
1029 if (rules->groups) {
1030 for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) {
1031 if (group->name) free(group->name);
1032 if (group->words) free(group->words);
1034 free(rules->groups);
1035 rules->num_groups= 0;
1036 rules->groups= NULL;