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;
85 FreeInputLine(InputLine *line)
87 if (line->line!=line->buf)
91 line->sz_line= DFLT_LINE_SIZE;
92 line->line= line->buf;
96 InputLineAddChar(InputLine *line,int ch)
98 if (line->num_line>=line->sz_line) {
99 if (line->line==line->buf) {
100 line->line= (char *)malloc(line->sz_line*2);
101 memcpy(line->line,line->buf,line->sz_line);
104 line->line=(char *)realloc((char *)line->line,line->sz_line*2);
108 line->line[line->num_line++]= ch;
112 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
113 (int)((l)->line[(l)->num_line++]= (c)):\
114 InputLineAddChar(l,c))
117 GetInputLine(FILE *file,InputLine *line,Bool checkbang)
120 Bool endOfFile,spacePending,slashPending,inComment;
123 while ((!endOfFile)&&(line->num_line==0)) {
124 spacePending= slashPending= inComment= False;
125 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
127 if ((ch=getc(file))==EOF)
147 else if (slashPending) {
156 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
161 if ((ch!='\n')&&(line->num_line>0))
170 if (checkbang && ch=='!') {
171 if (line->num_line!=0) {
172 PR_DEBUG("The '!' legal only at start of line\n");
173 PR_DEBUG("Line containing '!' ignored\n");
184 /* else line->num_line++;*/
186 if ((line->num_line==0)&&(endOfFile))
192 /***====================================================================***/
206 #define PART_MASK 0x000F
207 #define COMPONENT_MASK 0x03F0
209 static const char * cname[MAX_WORDS] = {
210 "model", "layout", "variant", "option",
211 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
214 typedef struct _RemapSpec {
223 typedef struct _FileSpec {
224 char * name[MAX_WORDS];
225 struct _FileSpec * pending;
230 const char * layout[XkbNumKbdGroups+1];
231 const char * variant[XkbNumKbdGroups+1];
233 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
235 #define NDX_BUFF_SIZE 4
237 /***====================================================================***/
240 get_index(char *str, int *ndx)
242 char ndx_buf[NDX_BUFF_SIZE];
250 end = strchr(str, ']');
255 if ( (end - str) >= NDX_BUFF_SIZE) {
259 strncpy(ndx_buf, str, end - str);
260 ndx_buf[end - str] = '\0';
261 *ndx = atoi(ndx_buf);
266 SetUpRemap(InputLine *line,RemapSpec *remap)
269 unsigned present, l_ndx_present, v_ndx_present;
272 _Xstrtokparams strtok_buf;
278 l_ndx_present = v_ndx_present = present= 0;
281 memset(remap, 0, sizeof(RemapSpec));
283 while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
288 if (strcmp(tok,"=")==0)
290 for (i=0;i<MAX_WORDS;i++) {
291 len = strlen(cname[i]);
292 if (strncmp(cname[i],tok,len)==0) {
293 if(strlen(tok) > len) {
294 char *end = get_index(tok+len, &ndx);
295 if ((i != LAYOUT && i != VARIANT) ||
296 *end != '\0' || ndx == -1)
298 if (ndx < 1 || ndx > XkbNumKbdGroups) {
299 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
300 PR_DEBUG1("Index must be in range 1..%d\n",
310 if (present&(1<<i)) {
311 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
312 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
313 PR_DEBUG1("Component \"%s\" listed twice\n",tok);
314 PR_DEBUG("Second definition ignored\n");
320 l_ndx_present |= 1 << ndx;
322 v_ndx_present |= 1 << ndx;
323 remap->remap[remap->num_remap].word= i;
324 remap->remap[remap->num_remap++].index= ndx;
330 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
334 if ((present&PART_MASK)==0) {
336 unsigned mask= PART_MASK;
337 fprintf(stderr,"Mapping needs at least one of ");
338 for (i=0; (i<MAX_WORDS); i++) {
341 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
342 else fprintf(stderr,"or \"%s\"\n",cname[i]);
345 fprintf(stderr,"Illegal mapping ignored\n");
350 if ((present&COMPONENT_MASK)==0) {
351 PR_DEBUG("Mapping needs at least one component\n");
352 PR_DEBUG("Illegal mapping ignored\n");
356 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
357 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
358 PR_DEBUG("Keymap cannot appear with other components\n");
359 PR_DEBUG("Illegal mapping ignored\n");
367 MatchOneOf(char *wanted,char *vals_defined)
370 int want_len = strlen(wanted);
372 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
374 next= strchr(str,',');
382 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
388 /***====================================================================***/
391 CheckLine( InputLine * line,
394 XkbRF_GroupPtr group)
399 _Xstrtokparams strtok_buf;
402 if (line->line[0]=='!') {
403 if (line->line[1] == '$' ||
404 (line->line[1] == ' ' && line->line[2] == '$')) {
405 char *gname = strchr(line->line, '$');
406 char *words = strchr(gname, ' ');
410 for (; *words; words++) {
411 if (*words != '=' && *words != ' ')
416 group->name = _XkbDupString(gname);
417 group->words = _XkbDupString(words);
418 for (i = 1, words = group->words; *words; words++) {
419 if ( *words == ' ') {
427 SetUpRemap(line,remap);
432 if (remap->num_remap==0) {
433 PR_DEBUG("Must have a mapping before first line of data\n");
434 PR_DEBUG("Illegal line of data ignored\n");
437 memset(&tmp, 0, sizeof(FileSpec));
439 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
441 if (strcmp(tok,"=")==0) {
445 if (nread>remap->num_remap) {
446 PR_DEBUG("Too many words on a line\n");
447 PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
450 tmp.name[remap->remap[nread].word]= tok;
451 if (*tok == '+' || *tok == '|')
454 if (nread<remap->num_remap) {
455 PR_DEBUG1("Too few words on a line: %s\n", line->line);
456 PR_DEBUG("line ignored\n");
461 rule->number = remap->number;
462 if (tmp.name[OPTION])
463 rule->flags|= XkbRF_Option;
465 rule->flags|= XkbRF_Append;
467 rule->flags|= XkbRF_Normal;
468 rule->model= _XkbDupString(tmp.name[MODEL]);
469 rule->layout= _XkbDupString(tmp.name[LAYOUT]);
470 rule->variant= _XkbDupString(tmp.name[VARIANT]);
471 rule->option= _XkbDupString(tmp.name[OPTION]);
473 rule->keycodes= _XkbDupString(tmp.name[KEYCODES]);
474 rule->symbols= _XkbDupString(tmp.name[SYMBOLS]);
475 rule->types= _XkbDupString(tmp.name[TYPES]);
476 rule->compat= _XkbDupString(tmp.name[COMPAT]);
477 rule->geometry= _XkbDupString(tmp.name[GEOMETRY]);
478 rule->keymap= _XkbDupString(tmp.name[KEYMAP]);
480 rule->layout_num = rule->variant_num = 0;
481 for (i = 0; i < nread; i++) {
482 if (remap->remap[i].index) {
483 if (remap->remap[i].word == LAYOUT)
484 rule->layout_num = remap->remap[i].index;
485 if (remap->remap[i].word == VARIANT)
486 rule->variant_num = remap->remap[i].index;
493 _Concat(char *str1,char *str2)
497 if ((!str1)||(!str2))
499 len= strlen(str1)+strlen(str2)+1;
500 str1= _XkbTypedRealloc(str1,len,char);
507 squeeze_spaces(char *p1)
510 for (p2 = p1; *p2; p2++) {
512 if (*p1 != ' ') p1++;
518 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
520 memset(mdefs, 0, sizeof(XkbRF_MultiDefsRec));
521 mdefs->model = defs->model;
522 mdefs->options = _XkbDupString(defs->options);
523 if (mdefs->options) squeeze_spaces(mdefs->options);
526 if (!strchr(defs->layout, ',')) {
527 mdefs->layout[0] = defs->layout;
531 p = _XkbDupString(defs->layout);
535 mdefs->layout[1] = p;
536 for (i = 2; i <= XkbNumKbdGroups; i++) {
537 if ((p = strchr(p, ','))) {
539 mdefs->layout[i] = p;
544 if (p && (p = strchr(p, ',')))
550 if (!strchr(defs->variant, ',')) {
551 mdefs->variant[0] = defs->variant;
555 p = _XkbDupString(defs->variant);
559 mdefs->variant[1] = p;
560 for (i = 2; i <= XkbNumKbdGroups; i++) {
561 if ((p = strchr(p, ','))) {
563 mdefs->variant[i] = p;
568 if (p && (p = strchr(p, ',')))
576 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
579 /* Avoid -Wcast-qual warnings. */
580 free((void *)(uintptr_t)defs->layout[1]);
581 free((void *)(uintptr_t)defs->variant[1]);
585 Apply(char *src, char **dst)
588 if (*src == '+' || *src == '!') {
589 *dst= _Concat(*dst, src);
592 *dst= _XkbDupString(src);
598 XkbRF_ApplyRule( XkbRF_RulePtr rule,
599 struct xkb_component_names * names)
601 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
603 Apply(rule->keycodes, &names->keycodes);
604 Apply(rule->symbols, &names->symbols);
605 Apply(rule->types, &names->types);
606 Apply(rule->compat, &names->compat);
607 Apply(rule->geometry, &names->geometry);
608 Apply(rule->keymap, &names->keymap);
612 CheckGroup( XkbRF_RulesPtr rules,
613 const char * group_name,
618 XkbRF_GroupPtr group;
620 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
621 if (! strcmp(group->name, group_name)) {
625 if (i == rules->num_groups)
627 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
628 if (! strcmp(p, name)) {
636 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
637 XkbRF_MultiDefsPtr mdefs,
638 struct xkb_component_names * names,
639 XkbRF_RulesPtr rules)
641 Bool pending = False;
643 if (rule->model != NULL) {
644 if(mdefs->model == NULL)
646 if (strcmp(rule->model, "*") == 0) {
649 if (rule->model[0] == '$') {
650 if (!CheckGroup(rules, rule->model, mdefs->model))
653 if (strcmp(rule->model, mdefs->model) != 0)
658 if (rule->option != NULL) {
659 if (mdefs->options == NULL)
661 if ((!MatchOneOf(rule->option,mdefs->options)))
665 if (rule->layout != NULL) {
666 if(mdefs->layout[rule->layout_num] == NULL ||
667 *mdefs->layout[rule->layout_num] == '\0')
669 if (strcmp(rule->layout, "*") == 0) {
672 if (rule->layout[0] == '$') {
673 if (!CheckGroup(rules, rule->layout,
674 mdefs->layout[rule->layout_num]))
677 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
682 if (rule->variant != NULL) {
683 if (mdefs->variant[rule->variant_num] == NULL ||
684 *mdefs->variant[rule->variant_num] == '\0')
686 if (strcmp(rule->variant, "*") == 0) {
689 if (rule->variant[0] == '$') {
690 if (!CheckGroup(rules, rule->variant,
691 mdefs->variant[rule->variant_num]))
694 if (strcmp(rule->variant,
695 mdefs->variant[rule->variant_num]) != 0)
701 rule->flags|= XkbRF_PendingMatch;
704 /* exact match, apply it now */
705 XkbRF_ApplyRule(rule,names);
710 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
715 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
716 rule->flags&= ~XkbRF_PendingMatch;
721 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,struct xkb_component_names * names)
726 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
727 if ((rule->flags&XkbRF_PendingMatch)==0)
729 XkbRF_ApplyRule(rule,names);
734 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
735 XkbRF_MultiDefsPtr mdefs,
736 struct xkb_component_names * names,
743 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
744 if ((rule->flags & flags) != flags)
746 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
747 if (skip && !(flags & XkbRF_Option)) {
748 for ( ;(i < rules->num_rules) && (rule->number == skip);
755 /***====================================================================***/
758 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
760 char *str, *outstr, *orig, *var;
764 str= index(name,'%');
771 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
780 str = get_index(var + 1, &ndx);
782 str = index(str,'%');
785 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
786 len+= strlen(mdefs->layout[ndx])+extra_len;
787 else if ((*var=='m')&&mdefs->model)
788 len+= strlen(mdefs->model)+extra_len;
789 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
790 len+= strlen(mdefs->variant[ndx])+extra_len;
791 if ((pfx=='(')&&(*str==')')) {
794 str= index(&str[0],'%');
796 name= (char *)malloc(len+1);
805 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
815 str = get_index(var + 1, &ndx);
819 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
820 if (pfx) *outstr++= pfx;
821 strcpy(outstr,mdefs->layout[ndx]);
822 outstr+= strlen(mdefs->layout[ndx]);
823 if (sfx) *outstr++= sfx;
825 else if ((*var=='m')&&(mdefs->model)) {
826 if (pfx) *outstr++= pfx;
827 strcpy(outstr,mdefs->model);
828 outstr+= strlen(mdefs->model);
829 if (sfx) *outstr++= sfx;
831 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
832 if (pfx) *outstr++= pfx;
833 strcpy(outstr,mdefs->variant[ndx]);
834 outstr+= strlen(mdefs->variant[ndx]);
835 if (sfx) *outstr++= sfx;
837 if ((pfx=='(')&&(*str==')'))
850 /***====================================================================***/
853 XkbcRF_GetComponents( XkbRF_RulesPtr rules,
854 XkbRF_VarDefsPtr defs,
855 struct xkb_component_names * names)
857 XkbRF_MultiDefsRec mdefs;
859 MakeMultiDefs(&mdefs, defs);
861 memset(names, 0, sizeof(struct xkb_component_names));
862 XkbRF_ClearPartialMatches(rules);
863 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
864 XkbRF_ApplyPartialMatches(rules, names);
865 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
866 XkbRF_ApplyPartialMatches(rules, names);
867 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
868 XkbRF_ApplyPartialMatches(rules, names);
871 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
873 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
875 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
877 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
879 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
881 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
883 FreeMultiDefs(&mdefs);
884 return (names->keycodes && names->symbols && names->types &&
885 names->compat && names->geometry ) || names->keymap;
889 XkbcRF_AddRule(XkbRF_RulesPtr rules)
891 if (rules->sz_rules<1) {
894 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
896 else if (rules->num_rules>=rules->sz_rules) {
898 rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
902 rules->sz_rules= rules->num_rules= 0;
904 fprintf(stderr,"Allocation failure in XkbcRF_AddRule\n");
908 memset(&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
909 return &rules->rules[rules->num_rules++];
912 static XkbRF_GroupPtr
913 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
915 if (rules->sz_groups<1) {
916 rules->sz_groups= 16;
917 rules->num_groups= 0;
918 rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
920 else if (rules->num_groups >= rules->sz_groups) {
921 rules->sz_groups *= 2;
922 rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups,
925 if (!rules->groups) {
926 rules->sz_groups= rules->num_groups= 0;
930 memset(&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec));
931 return &rules->groups[rules->num_groups++];
935 XkbcRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
939 XkbRF_RuleRec trule,*rule;
940 XkbRF_GroupRec tgroup,*group;
942 if (!(rules && file))
944 memset(&remap, 0, sizeof(RemapSpec));
945 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
946 InitInputLine(&line);
947 while (GetInputLine(file,&line,True)) {
948 if (CheckLine(&line,&remap,&trule,&tgroup)) {
950 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
952 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
955 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
957 memset(&trule, 0, sizeof(XkbRF_RuleRec));
963 FreeInputLine(&line);
968 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
972 for (i=0;i<var->num_desc;i++) {
973 free(var->desc[i].name);
974 free(var->desc[i].desc);
975 var->desc[i].name= var->desc[i].desc= NULL;
982 XkbcRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
986 XkbRF_GroupPtr group;
990 XkbRF_ClearVarDescriptions(&rules->models);
991 XkbRF_ClearVarDescriptions(&rules->layouts);
992 XkbRF_ClearVarDescriptions(&rules->variants);
993 XkbRF_ClearVarDescriptions(&rules->options);
995 for (i = 0; i < rules->num_extra; i++) {
996 XkbRF_ClearVarDescriptions(&rules->extra[i]);
999 rules->num_extra= rules->sz_extra= 0;
1002 for (i=0, rule = rules->rules; i < rules->num_rules && rules; i++, rule++) {
1005 free(rule->variant);
1007 free(rule->keycodes);
1008 free(rule->symbols);
1011 free(rule->geometry);
1013 memset(rule, 0, sizeof(XkbRF_RuleRec));
1016 rules->num_rules= rules->sz_rules= 0;
1019 for (i=0, group = rules->groups; i < rules->num_groups && group; i++, group++) {
1023 free(rules->groups);
1024 rules->num_groups= 0;
1025 rules->groups= NULL;