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 ********************************************************/
33 #define DFLT_LINE_SIZE 128
38 char buf[DFLT_LINE_SIZE];
43 input_line_init(struct input_line *line)
45 line->size = DFLT_LINE_SIZE;
47 line->line = line->buf;
51 input_line_deinit(struct input_line *line)
53 if (line->line != line->buf)
56 line->size = DFLT_LINE_SIZE;
57 line->line = line->buf;
61 input_line_add_char(struct input_line *line, int ch)
63 if (line->offset >= line->size) {
64 if (line->line == line->buf) {
65 line->line = malloc(line->size * 2);
66 memcpy(line->line, line->buf, line->size);
69 line->line = realloc(line->line, line->size * 2);
75 line->line[line->offset++] = ch;
80 input_line_get(FILE *file, struct input_line *line)
83 bool end_of_file = false;
88 while (!end_of_file && line->offset == 0) {
89 space_pending = slash_pending = in_comment = false;
91 while ((ch = getc(file)) != '\n' && ch != EOF) {
110 slash_pending = false;
113 slash_pending = true;
121 input_line_add_char(line, ' ');
122 space_pending = false;
125 input_line_add_char(line, '/');
126 slash_pending = false;
130 while (isspace(ch) && ch != '\n' && ch != EOF)
136 if (ch != '\n' && line->offset > 0)
137 space_pending = true;
143 input_line_add_char(line, ' ');
144 space_pending = false;
148 if (line->offset != 0) {
149 WARN("The '!' is legal only at start of line\n");
150 ACTION("Line containing '!' ignored\n");
156 input_line_add_char(line, ch);
164 if (line->offset == 0 && end_of_file)
167 input_line_add_char(line, '\0');
171 /***====================================================================***/
185 #define PART_MASK 0x000F
186 #define COMPONENT_MASK 0x03F0
188 static const char * cname[MAX_WORDS] = {
189 "model", "layout", "variant", "option",
190 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
198 } XkbRF_VarDefsRec, *XkbRF_VarDefsPtr;
200 typedef struct _RemapSpec {
209 typedef struct _FileSpec {
210 char * name[MAX_WORDS];
211 struct _FileSpec * pending;
216 const char * layout[XkbNumKbdGroups+1];
217 const char * variant[XkbNumKbdGroups+1];
219 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
221 typedef struct _XkbRF_VarDesc {
224 } XkbRF_VarDescRec, *XkbRF_VarDescPtr;
226 typedef struct _XkbRF_DescribeVars {
229 XkbRF_VarDescPtr desc;
230 } XkbRF_DescribeVarsRec,*XkbRF_DescribeVarsPtr;
232 typedef struct _XkbRF_Group {
236 } XkbRF_GroupRec, *XkbRF_GroupPtr;
238 #define XkbRF_PendingMatch (1L<<1)
239 #define XkbRF_Option (1L<<2)
240 #define XkbRF_Append (1L<<3)
241 #define XkbRF_Normal (1L<<4)
242 #define XkbRF_Invalid (1L<<5)
244 typedef struct _XkbRF_Rule {
259 } XkbRF_RuleRec,*XkbRF_RulePtr;
261 typedef struct XkbRF_Rules {
262 XkbRF_DescribeVarsRec models;
263 XkbRF_DescribeVarsRec layouts;
264 XkbRF_DescribeVarsRec variants;
265 XkbRF_DescribeVarsRec options;
272 XkbRF_GroupPtr groups;
273 } XkbRF_RulesRec, *XkbRF_RulesPtr;
275 #define NDX_BUFF_SIZE 4
277 /***====================================================================***/
280 get_index(char *str, int *ndx)
282 char ndx_buf[NDX_BUFF_SIZE];
290 end = strchr(str, ']');
295 if ( (end - str) >= NDX_BUFF_SIZE) {
299 strncpy(ndx_buf, str, end - str);
300 ndx_buf[end - str] = '\0';
301 *ndx = atoi(ndx_buf);
306 SetUpRemap(struct input_line *line,RemapSpec *remap)
309 unsigned present, l_ndx_present, v_ndx_present;
316 l_ndx_present = v_ndx_present = present= 0;
319 memset(remap, 0, sizeof(RemapSpec));
321 while ((tok = strtok_r(str, " ", &strtok_buf)) != NULL) {
324 if (strcmp(tok,"=")==0)
326 for (i=0;i<MAX_WORDS;i++) {
327 len = strlen(cname[i]);
328 if (strncmp(cname[i],tok,len)==0) {
329 if(strlen(tok) > len) {
330 char *end = get_index(tok+len, &ndx);
331 if ((i != LAYOUT && i != VARIANT) ||
332 *end != '\0' || ndx == -1)
334 if (ndx < 1 || ndx > XkbNumKbdGroups) {
335 WARN("Illegal %s index: %d\n", cname[i], ndx);
336 WARN("Index must be in range 1..%d\n", XkbNumKbdGroups);
345 if (present&(1<<i)) {
346 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
347 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
348 WARN("Component \"%s\" listed twice\n", tok);
349 ACTION("Second definition ignored\n");
355 l_ndx_present |= 1 << ndx;
357 v_ndx_present |= 1 << ndx;
358 remap->remap[remap->num_remap].word= i;
359 remap->remap[remap->num_remap++].index= ndx;
365 WARN("Unknown component \"%s\"\n", tok);
369 if ((present&PART_MASK)==0) {
370 unsigned mask= PART_MASK;
372 /* FIXME: Use log function instead of fprintf. */
373 WARN("Mapping needs at least one of ");
374 for (i=0; (i<MAX_WORDS); i++) {
377 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
378 else fprintf(stderr,"or \"%s\"\n",cname[i]);
381 ACTION("Illegal mapping ignored\n");
386 if ((present&COMPONENT_MASK)==0) {
387 WARN("Mapping needs at least one component\n");
388 ACTION("Illegal mapping ignored\n");
392 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
393 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
394 WARN("Keymap cannot appear with other components\n");
395 ACTION("Illegal mapping ignored\n");
403 MatchOneOf(char *wanted,char *vals_defined)
406 int want_len = strlen(wanted);
408 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
410 next= strchr(str,',');
418 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
424 /***====================================================================***/
427 CheckLine( struct input_line * line,
430 XkbRF_GroupPtr group)
438 if (line->line[0]=='!') {
439 if (line->line[1] == '$' ||
440 (line->line[1] == ' ' && line->line[2] == '$')) {
441 char *gname = strchr(line->line, '$');
442 char *words = strchr(gname, ' ');
446 for (; *words; words++) {
447 if (*words != '=' && *words != ' ')
452 group->name = uDupString(gname);
453 group->words = uDupString(words);
454 for (i = 1, words = group->words; *words; words++) {
455 if ( *words == ' ') {
463 SetUpRemap(line,remap);
468 if (remap->num_remap==0) {
469 WARN("Must have a mapping before first line of data\n");
470 ACTION("Illegal line of data ignored\n");
473 memset(&tmp, 0, sizeof(FileSpec));
475 for (nread = 0; (tok = strtok_r(str, " ", &strtok_buf)) != NULL; nread++) {
477 if (strcmp(tok,"=")==0) {
481 if (nread>remap->num_remap) {
482 WARN("Too many words on a line\n");
483 ACTION("Extra word \"%s\" ignored\n",tok);
486 tmp.name[remap->remap[nread].word]= tok;
487 if (*tok == '+' || *tok == '|')
490 if (nread<remap->num_remap) {
491 WARN("Too few words on a line: %s\n", line->line);
492 ACTION("line ignored\n");
497 rule->number = remap->number;
498 if (tmp.name[OPTION])
499 rule->flags|= XkbRF_Option;
501 rule->flags|= XkbRF_Append;
503 rule->flags|= XkbRF_Normal;
504 rule->model= uDupString(tmp.name[MODEL]);
505 rule->layout= uDupString(tmp.name[LAYOUT]);
506 rule->variant= uDupString(tmp.name[VARIANT]);
507 rule->option= uDupString(tmp.name[OPTION]);
509 rule->keycodes= uDupString(tmp.name[KEYCODES]);
510 rule->symbols= uDupString(tmp.name[SYMBOLS]);
511 rule->types= uDupString(tmp.name[TYPES]);
512 rule->compat= uDupString(tmp.name[COMPAT]);
513 rule->keymap= uDupString(tmp.name[KEYMAP]);
515 rule->layout_num = rule->variant_num = 0;
516 for (i = 0; i < nread; i++) {
517 if (remap->remap[i].index) {
518 if (remap->remap[i].word == LAYOUT)
519 rule->layout_num = remap->remap[i].index;
520 if (remap->remap[i].word == VARIANT)
521 rule->variant_num = remap->remap[i].index;
528 _Concat(char *str1,char *str2)
532 if ((!str1)||(!str2))
534 len= strlen(str1)+strlen(str2)+1;
535 str1 = uTypedRealloc(str1, len, char);
542 squeeze_spaces(char *p1)
545 for (p2 = p1; *p2; p2++) {
547 if (*p1 != ' ') p1++;
553 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, const XkbRF_VarDefsPtr defs)
555 memset(mdefs, 0, sizeof(XkbRF_MultiDefsRec));
556 mdefs->model = defs->model;
557 mdefs->options = uDupString(defs->options);
558 if (mdefs->options) squeeze_spaces(mdefs->options);
561 if (!strchr(defs->layout, ',')) {
562 mdefs->layout[0] = defs->layout;
566 p = uDupString(defs->layout);
570 mdefs->layout[1] = p;
571 for (i = 2; i <= XkbNumKbdGroups; i++) {
572 if ((p = strchr(p, ','))) {
574 mdefs->layout[i] = p;
579 if (p && (p = strchr(p, ',')))
585 if (!strchr(defs->variant, ',')) {
586 mdefs->variant[0] = defs->variant;
590 p = uDupString(defs->variant);
594 mdefs->variant[1] = p;
595 for (i = 2; i <= XkbNumKbdGroups; i++) {
596 if ((p = strchr(p, ','))) {
598 mdefs->variant[i] = p;
603 if (p && (p = strchr(p, ',')))
611 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
614 free(UNCONSTIFY(defs->layout[1]));
615 free(UNCONSTIFY(defs->variant[1]));
619 Apply(char *src, char **dst)
622 if (*src == '+' || *src == '!') {
623 *dst= _Concat(*dst, src);
626 *dst= uDupString(src);
632 XkbRF_ApplyRule( XkbRF_RulePtr rule,
633 struct xkb_component_names * names)
635 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
637 Apply(rule->keycodes, &names->keycodes);
638 Apply(rule->symbols, &names->symbols);
639 Apply(rule->types, &names->types);
640 Apply(rule->compat, &names->compat);
641 Apply(rule->keymap, &names->keymap);
645 CheckGroup( XkbRF_RulesPtr rules,
646 const char * group_name,
651 XkbRF_GroupPtr group;
653 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
654 if (! strcmp(group->name, group_name)) {
658 if (i == rules->num_groups)
660 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
661 if (! strcmp(p, name)) {
669 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
670 XkbRF_MultiDefsPtr mdefs,
671 struct xkb_component_names * names,
672 XkbRF_RulesPtr rules)
674 bool pending = false;
676 if (rule->model != NULL) {
677 if(mdefs->model == NULL)
679 if (strcmp(rule->model, "*") == 0) {
682 if (rule->model[0] == '$') {
683 if (!CheckGroup(rules, rule->model, mdefs->model))
686 if (strcmp(rule->model, mdefs->model) != 0)
691 if (rule->option != NULL) {
692 if (mdefs->options == NULL)
694 if ((!MatchOneOf(rule->option,mdefs->options)))
698 if (rule->layout != NULL) {
699 if(mdefs->layout[rule->layout_num] == NULL ||
700 *mdefs->layout[rule->layout_num] == '\0')
702 if (strcmp(rule->layout, "*") == 0) {
705 if (rule->layout[0] == '$') {
706 if (!CheckGroup(rules, rule->layout,
707 mdefs->layout[rule->layout_num]))
710 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
715 if (rule->variant != NULL) {
716 if (mdefs->variant[rule->variant_num] == NULL ||
717 *mdefs->variant[rule->variant_num] == '\0')
719 if (strcmp(rule->variant, "*") == 0) {
722 if (rule->variant[0] == '$') {
723 if (!CheckGroup(rules, rule->variant,
724 mdefs->variant[rule->variant_num]))
727 if (strcmp(rule->variant,
728 mdefs->variant[rule->variant_num]) != 0)
734 rule->flags|= XkbRF_PendingMatch;
737 /* exact match, apply it now */
738 XkbRF_ApplyRule(rule,names);
743 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
748 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
749 rule->flags&= ~XkbRF_PendingMatch;
754 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,struct xkb_component_names * names)
759 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
760 if ((rule->flags&XkbRF_PendingMatch)==0)
762 XkbRF_ApplyRule(rule,names);
767 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
768 XkbRF_MultiDefsPtr mdefs,
769 struct xkb_component_names * names,
776 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
777 if ((rule->flags & flags) != flags)
779 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
780 if (skip && !(flags & XkbRF_Option)) {
781 for ( ;(i < rules->num_rules) && (rule->number == skip);
788 /***====================================================================***/
791 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
793 char *str, *outstr, *orig, *var;
801 str= strchr(name,'%');
808 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
817 str = get_index(var + 1, &ndx);
819 str = strchr(str,'%');
822 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
823 len+= strlen(mdefs->layout[ndx])+extra_len;
824 else if ((*var=='m')&&mdefs->model)
825 len+= strlen(mdefs->model)+extra_len;
826 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
827 len+= strlen(mdefs->variant[ndx])+extra_len;
828 if ((pfx=='(')&&(*str==')')) {
831 str= strchr(&str[0],'%');
833 name = malloc(len + 1);
842 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
852 str = get_index(var + 1, &ndx);
856 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
857 if (pfx) *outstr++= pfx;
858 strcpy(outstr,mdefs->layout[ndx]);
859 outstr+= strlen(mdefs->layout[ndx]);
860 if (sfx) *outstr++= sfx;
862 else if ((*var=='m')&&(mdefs->model)) {
863 if (pfx) *outstr++= pfx;
864 strcpy(outstr,mdefs->model);
865 outstr+= strlen(mdefs->model);
866 if (sfx) *outstr++= sfx;
868 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
869 if (pfx) *outstr++= pfx;
870 strcpy(outstr,mdefs->variant[ndx]);
871 outstr+= strlen(mdefs->variant[ndx]);
872 if (sfx) *outstr++= sfx;
874 if ((pfx=='(')&&(*str==')'))
887 /***====================================================================***/
890 XkbcRF_GetComponents(struct XkbRF_Rules *rules, const XkbRF_VarDefsPtr defs,
891 struct xkb_component_names *names)
893 XkbRF_MultiDefsRec mdefs;
895 MakeMultiDefs(&mdefs, defs);
897 memset(names, 0, sizeof(struct xkb_component_names));
898 XkbRF_ClearPartialMatches(rules);
899 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
900 XkbRF_ApplyPartialMatches(rules, names);
901 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
902 XkbRF_ApplyPartialMatches(rules, names);
903 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
904 XkbRF_ApplyPartialMatches(rules, names);
906 names->keycodes = XkbRF_SubstituteVars(names->keycodes, &mdefs);
907 names->symbols = XkbRF_SubstituteVars(names->symbols, &mdefs);
908 names->types = XkbRF_SubstituteVars(names->types, &mdefs);
909 names->compat = XkbRF_SubstituteVars(names->compat, &mdefs);
910 names->keymap = XkbRF_SubstituteVars(names->keymap, &mdefs);
912 FreeMultiDefs(&mdefs);
913 return (names->keycodes && names->symbols && names->types &&
914 names->compat) || names->keymap;
918 XkbcRF_AddRule(XkbRF_RulesPtr rules)
920 if (rules->sz_rules<1) {
923 rules->rules= uTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
925 else if (rules->num_rules>=rules->sz_rules) {
927 rules->rules= uTypedRealloc(rules->rules,rules->sz_rules,
931 rules->sz_rules= rules->num_rules= 0;
934 memset(&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
935 return &rules->rules[rules->num_rules++];
938 static XkbRF_GroupPtr
939 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
941 if (rules->sz_groups<1) {
942 rules->sz_groups= 16;
943 rules->num_groups= 0;
944 rules->groups= uTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
946 else if (rules->num_groups >= rules->sz_groups) {
947 rules->sz_groups *= 2;
948 rules->groups= uTypedRealloc(rules->groups,rules->sz_groups,
951 if (!rules->groups) {
952 rules->sz_groups= rules->num_groups= 0;
956 memset(&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec));
957 return &rules->groups[rules->num_groups++];
960 static XkbRF_RulesPtr
961 XkbcRF_LoadRules(FILE *file)
963 struct input_line line;
965 XkbRF_RuleRec trule,*rule;
966 XkbRF_GroupRec tgroup,*group;
967 XkbRF_RulesPtr rules;
969 rules = calloc(1, sizeof(*rules));
973 memset(&remap, 0, sizeof(RemapSpec));
974 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
975 input_line_init(&line);
976 while (input_line_get(file, &line)) {
977 if (CheckLine(&line,&remap,&trule,&tgroup)) {
979 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
981 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
984 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
986 memset(&trule, 0, sizeof(XkbRF_RuleRec));
992 input_line_deinit(&line);
997 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
1001 for (i=0;i<var->num_desc;i++) {
1002 free(var->desc[i].name);
1003 free(var->desc[i].desc);
1004 var->desc[i].name= var->desc[i].desc= NULL;
1011 XkbcRF_Free(XkbRF_RulesPtr rules)
1015 XkbRF_GroupPtr group;
1019 XkbRF_ClearVarDescriptions(&rules->models);
1020 XkbRF_ClearVarDescriptions(&rules->layouts);
1021 XkbRF_ClearVarDescriptions(&rules->variants);
1022 XkbRF_ClearVarDescriptions(&rules->options);
1024 for (i=0, rule = rules->rules; i < rules->num_rules && rules; i++, rule++) {
1027 free(rule->variant);
1029 free(rule->keycodes);
1030 free(rule->symbols);
1037 for (i=0, group = rules->groups; i < rules->num_groups && group; i++, group++) {
1041 free(rules->groups);
1046 struct xkb_component_names *
1047 xkb_components_from_rules(struct xkb_context *ctx,
1048 const struct xkb_rule_names *rmlvo)
1053 XkbRF_RulesPtr loaded;
1054 struct xkb_component_names *names = NULL;
1055 XkbRF_VarDefsRec defs = {
1056 .model = rmlvo->model,
1057 .layout = rmlvo->layout,
1058 .variant = rmlvo->variant,
1059 .options = rmlvo->options,
1062 rulesFile = XkbFindFileInPath(ctx, rmlvo->rules, XkmRulesFile,
1065 ERROR("could not find \"%s\" rules in XKB path\n", rmlvo->rules);
1066 ERROR("%d include paths searched:\n",
1067 xkb_context_num_include_paths(ctx));
1068 for (i = 0; i < xkb_context_num_include_paths(ctx); i++)
1069 ERROR("\t%s\n", xkb_context_include_path_get(ctx, i));
1073 loaded = XkbcRF_LoadRules(rulesFile);
1075 ERROR("failed to load XKB rules \"%s\"\n", rulesPath);
1079 names = calloc(1, sizeof(*names));
1081 ERROR("failed to allocate XKB components\n");
1085 if (!XkbcRF_GetComponents(loaded, &defs, names)) {
1086 free(names->keymap);
1087 free(names->keycodes);
1089 free(names->compat);
1090 free(names->symbols);
1093 ERROR("no components returned from XKB rules \"%s\"\n", rulesPath);
1097 XkbcRF_Free(loaded);