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 const 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 const char * layout[XkbNumKbdGroups+1];
233 const 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 p = _XkbDupString(defs->layout);
538 mdefs->layout[1] = p;
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 p = _XkbDupString(defs->variant);
562 mdefs->variant[1] = p;
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)
582 /* Avoid -Wcast-qual warnings. */
583 free((void *)(uintptr_t)defs->layout[1]);
584 free((void *)(uintptr_t)defs->variant[1]);
588 Apply(char *src, char **dst)
591 if (*src == '+' || *src == '!') {
592 *dst= _Concat(*dst, src);
595 *dst= _XkbDupString(src);
601 XkbRF_ApplyRule( XkbRF_RulePtr rule,
602 struct xkb_component_names * names)
604 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
606 Apply(rule->keycodes, &names->keycodes);
607 Apply(rule->symbols, &names->symbols);
608 Apply(rule->types, &names->types);
609 Apply(rule->compat, &names->compat);
610 Apply(rule->geometry, &names->geometry);
611 Apply(rule->keymap, &names->keymap);
615 CheckGroup( XkbRF_RulesPtr rules,
616 const char * group_name,
621 XkbRF_GroupPtr group;
623 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
624 if (! strcmp(group->name, group_name)) {
628 if (i == rules->num_groups)
630 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
631 if (! strcmp(p, name)) {
639 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
640 XkbRF_MultiDefsPtr mdefs,
641 struct xkb_component_names * names,
642 XkbRF_RulesPtr rules)
644 Bool pending = False;
646 if (rule->model != NULL) {
647 if(mdefs->model == NULL)
649 if (strcmp(rule->model, "*") == 0) {
652 if (rule->model[0] == '$') {
653 if (!CheckGroup(rules, rule->model, mdefs->model))
656 if (strcmp(rule->model, mdefs->model) != 0)
661 if (rule->option != NULL) {
662 if (mdefs->options == NULL)
664 if ((!MatchOneOf(rule->option,mdefs->options)))
668 if (rule->layout != NULL) {
669 if(mdefs->layout[rule->layout_num] == NULL ||
670 *mdefs->layout[rule->layout_num] == '\0')
672 if (strcmp(rule->layout, "*") == 0) {
675 if (rule->layout[0] == '$') {
676 if (!CheckGroup(rules, rule->layout,
677 mdefs->layout[rule->layout_num]))
680 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
685 if (rule->variant != NULL) {
686 if (mdefs->variant[rule->variant_num] == NULL ||
687 *mdefs->variant[rule->variant_num] == '\0')
689 if (strcmp(rule->variant, "*") == 0) {
692 if (rule->variant[0] == '$') {
693 if (!CheckGroup(rules, rule->variant,
694 mdefs->variant[rule->variant_num]))
697 if (strcmp(rule->variant,
698 mdefs->variant[rule->variant_num]) != 0)
704 rule->flags|= XkbRF_PendingMatch;
707 /* exact match, apply it now */
708 XkbRF_ApplyRule(rule,names);
713 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
718 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
719 rule->flags&= ~XkbRF_PendingMatch;
724 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,struct xkb_component_names * names)
729 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
730 if ((rule->flags&XkbRF_PendingMatch)==0)
732 XkbRF_ApplyRule(rule,names);
737 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
738 XkbRF_MultiDefsPtr mdefs,
739 struct xkb_component_names * names,
746 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
747 if ((rule->flags & flags) != flags)
749 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
750 if (skip && !(flags & XkbRF_Option)) {
751 for ( ;(i < rules->num_rules) && (rule->number == skip);
758 /***====================================================================***/
761 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
763 char *str, *outstr, *orig, *var;
767 str= index(name,'%');
774 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
783 str = get_index(var + 1, &ndx);
785 str = index(str,'%');
788 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
789 len+= strlen(mdefs->layout[ndx])+extra_len;
790 else if ((*var=='m')&&mdefs->model)
791 len+= strlen(mdefs->model)+extra_len;
792 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
793 len+= strlen(mdefs->variant[ndx])+extra_len;
794 if ((pfx=='(')&&(*str==')')) {
797 str= index(&str[0],'%');
799 name= (char *)malloc(len+1);
808 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
818 str = get_index(var + 1, &ndx);
822 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
823 if (pfx) *outstr++= pfx;
824 strcpy(outstr,mdefs->layout[ndx]);
825 outstr+= strlen(mdefs->layout[ndx]);
826 if (sfx) *outstr++= sfx;
828 else if ((*var=='m')&&(mdefs->model)) {
829 if (pfx) *outstr++= pfx;
830 strcpy(outstr,mdefs->model);
831 outstr+= strlen(mdefs->model);
832 if (sfx) *outstr++= sfx;
834 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
835 if (pfx) *outstr++= pfx;
836 strcpy(outstr,mdefs->variant[ndx]);
837 outstr+= strlen(mdefs->variant[ndx]);
838 if (sfx) *outstr++= sfx;
840 if ((pfx=='(')&&(*str==')'))
853 /***====================================================================***/
856 XkbcRF_GetComponents( XkbRF_RulesPtr rules,
857 XkbRF_VarDefsPtr defs,
858 struct xkb_component_names * names)
860 XkbRF_MultiDefsRec mdefs;
862 MakeMultiDefs(&mdefs, defs);
864 bzero((char *)names,sizeof(struct xkb_component_names));
865 XkbRF_ClearPartialMatches(rules);
866 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
867 XkbRF_ApplyPartialMatches(rules, names);
868 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
869 XkbRF_ApplyPartialMatches(rules, names);
870 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
871 XkbRF_ApplyPartialMatches(rules, names);
874 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
876 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
878 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
880 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
882 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
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;
892 XkbcRF_AddRule(XkbRF_RulesPtr rules)
894 if (rules->sz_rules<1) {
897 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
899 else if (rules->num_rules>=rules->sz_rules) {
901 rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
905 rules->sz_rules= rules->num_rules= 0;
907 fprintf(stderr,"Allocation failure in XkbcRF_AddRule\n");
911 bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec));
912 return &rules->rules[rules->num_rules++];
915 static XkbRF_GroupPtr
916 XkbcRF_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,
928 if (!rules->groups) {
929 rules->sz_groups= rules->num_groups= 0;
933 bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec));
934 return &rules->groups[rules->num_groups++];
938 XkbcRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
942 XkbRF_RuleRec trule,*rule;
943 XkbRF_GroupRec tgroup,*group;
945 if (!(rules && file))
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)) {
953 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
955 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
958 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
960 bzero((char *)&trule,sizeof(XkbRF_RuleRec));
966 FreeInputLine(&line);
971 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
975 for (i=0;i<var->num_desc;i++) {
976 free(var->desc[i].name);
977 free(var->desc[i].desc);
978 var->desc[i].name= var->desc[i].desc= NULL;
986 XkbcRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
990 XkbRF_GroupPtr group;
994 XkbRF_ClearVarDescriptions(&rules->models);
995 XkbRF_ClearVarDescriptions(&rules->layouts);
996 XkbRF_ClearVarDescriptions(&rules->variants);
997 XkbRF_ClearVarDescriptions(&rules->options);
999 for (i = 0; i < rules->num_extra; i++) {
1000 XkbRF_ClearVarDescriptions(&rules->extra[i]);
1003 rules->num_extra= rules->sz_extra= 0;
1006 for (i=0, rule = rules->rules; i < rules->num_rules && rules; i++, rule++) {
1009 free(rule->variant);
1011 free(rule->keycodes);
1012 free(rule->symbols);
1015 free(rule->geometry);
1017 bzero((char *)rule,sizeof(XkbRF_RuleRec));
1020 rules->num_rules= rules->sz_rules= 0;
1023 for (i=0, group = rules->groups; i < rules->num_groups && group; i++, group++) {
1027 free(rules->groups);
1028 rules->num_groups= 0;
1029 rules->groups= NULL;