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"
210 char *name[MAX_WORDS];
211 struct file_spec *pending;
216 const char *layout[XkbNumKbdGroups + 1];
217 const char *variant[XkbNumKbdGroups + 1];
226 struct describe_vars {
229 struct var_desc *desc;
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)
264 struct describe_vars models;
265 struct describe_vars layouts;
266 struct describe_vars variants;
267 struct describe_vars options;
275 struct group *groups;
278 /***====================================================================***/
281 * Resolve numeric index, such as "[4]" in layout[4]. Missing index
285 get_index(char *str, int *ndx)
287 int empty = 0, consumed = 0, num;
289 sscanf(str, "[%n%d]%n", &empty, &num, &consumed);
293 } else if (empty > 0) {
303 SetUpRemap(struct input_line *line, struct remap_spec *remap)
306 unsigned present, l_ndx_present, v_ndx_present;
313 l_ndx_present = v_ndx_present = present= 0;
316 memset(remap, 0, sizeof(*remap));
318 while ((tok = strtok_r(str, " ", &strtok_buf)) != NULL) {
321 if (strcmp(tok,"=")==0)
323 for (i=0;i<MAX_WORDS;i++) {
324 len = strlen(cname[i]);
325 if (strncmp(cname[i],tok,len)==0) {
326 if(strlen(tok) > len) {
327 char *end = get_index(tok+len, &ndx);
328 if ((i != LAYOUT && i != VARIANT) ||
329 *end != '\0' || ndx == -1)
331 if (ndx < 1 || ndx > XkbNumKbdGroups) {
332 WARN("Illegal %s index: %d\n", cname[i], ndx);
333 WARN("Index must be in range 1..%d\n", XkbNumKbdGroups);
342 if (present&(1<<i)) {
343 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
344 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
345 WARN("Component \"%s\" listed twice\n", tok);
346 ACTION("Second definition ignored\n");
352 l_ndx_present |= 1 << ndx;
354 v_ndx_present |= 1 << ndx;
355 remap->remap[remap->num_remap].word= i;
356 remap->remap[remap->num_remap++].index= ndx;
362 WARN("Unknown component \"%s\"\n", tok);
366 if ((present&PART_MASK)==0) {
367 unsigned mask= PART_MASK;
369 /* FIXME: Use log function instead of fprintf. */
370 WARN("Mapping needs at least one of ");
371 for (i=0; (i<MAX_WORDS); i++) {
374 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
375 else fprintf(stderr,"or \"%s\"\n",cname[i]);
378 ACTION("Illegal mapping ignored\n");
383 if ((present&COMPONENT_MASK)==0) {
384 WARN("Mapping needs at least one component\n");
385 ACTION("Illegal mapping ignored\n");
389 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
390 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
391 WARN("Keymap cannot appear with other components\n");
392 ACTION("Illegal mapping ignored\n");
400 MatchOneOf(char *wanted,char *vals_defined)
403 int want_len = strlen(wanted);
405 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
407 next= strchr(str,',');
415 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
421 /***====================================================================***/
424 CheckLine(struct input_line *line, struct remap_spec *remap,
425 struct rule *rule, struct group *group)
429 struct file_spec tmp;
433 if (line->line[0]=='!') {
434 if (line->line[1] == '$' ||
435 (line->line[1] == ' ' && line->line[2] == '$')) {
436 char *gname = strchr(line->line, '$');
437 char *words = strchr(gname, ' ');
441 for (; *words; words++) {
442 if (*words != '=' && *words != ' ')
447 group->name = uDupString(gname);
448 group->words = uDupString(words);
449 for (i = 1, words = group->words; *words; words++) {
450 if ( *words == ' ') {
458 SetUpRemap(line,remap);
463 if (remap->num_remap==0) {
464 WARN("Must have a mapping before first line of data\n");
465 ACTION("Illegal line of data ignored\n");
468 memset(&tmp, 0, sizeof(tmp));
470 for (nread = 0; (tok = strtok_r(str, " ", &strtok_buf)) != NULL; nread++) {
472 if (strcmp(tok,"=")==0) {
476 if (nread>remap->num_remap) {
477 WARN("Too many words on a line\n");
478 ACTION("Extra word \"%s\" ignored\n",tok);
481 tmp.name[remap->remap[nread].word]= tok;
482 if (*tok == '+' || *tok == '|')
485 if (nread<remap->num_remap) {
486 WARN("Too few words on a line: %s\n", line->line);
487 ACTION("line ignored\n");
492 rule->number = remap->number;
493 if (tmp.name[OPTION])
494 rule->flags|= XkbRF_Option;
496 rule->flags|= XkbRF_Append;
498 rule->flags|= XkbRF_Normal;
499 rule->model= uDupString(tmp.name[MODEL]);
500 rule->layout= uDupString(tmp.name[LAYOUT]);
501 rule->variant= uDupString(tmp.name[VARIANT]);
502 rule->option= uDupString(tmp.name[OPTION]);
504 rule->keycodes= uDupString(tmp.name[KEYCODES]);
505 rule->symbols= uDupString(tmp.name[SYMBOLS]);
506 rule->types= uDupString(tmp.name[TYPES]);
507 rule->compat= uDupString(tmp.name[COMPAT]);
508 rule->keymap= uDupString(tmp.name[KEYMAP]);
510 rule->layout_num = rule->variant_num = 0;
511 for (i = 0; i < nread; i++) {
512 if (remap->remap[i].index) {
513 if (remap->remap[i].word == LAYOUT)
514 rule->layout_num = remap->remap[i].index;
515 if (remap->remap[i].word == VARIANT)
516 rule->variant_num = remap->remap[i].index;
523 _Concat(char *str1,char *str2)
527 if ((!str1)||(!str2))
529 len= strlen(str1)+strlen(str2)+1;
530 str1 = uTypedRealloc(str1, len, char);
537 squeeze_spaces(char *p1)
540 for (p2 = p1; *p2; p2++) {
542 if (*p1 != ' ') p1++;
548 MakeMultiDefs(struct multi_defs *mdefs, const struct var_defs *defs)
550 memset(mdefs, 0, sizeof(*mdefs));
551 mdefs->model = defs->model;
552 mdefs->options = uDupString(defs->options);
553 if (mdefs->options) squeeze_spaces(mdefs->options);
556 if (!strchr(defs->layout, ',')) {
557 mdefs->layout[0] = defs->layout;
561 p = uDupString(defs->layout);
565 mdefs->layout[1] = p;
566 for (i = 2; i <= XkbNumKbdGroups; i++) {
567 if ((p = strchr(p, ','))) {
569 mdefs->layout[i] = p;
574 if (p && (p = strchr(p, ',')))
580 if (!strchr(defs->variant, ',')) {
581 mdefs->variant[0] = defs->variant;
585 p = uDupString(defs->variant);
589 mdefs->variant[1] = p;
590 for (i = 2; i <= XkbNumKbdGroups; i++) {
591 if ((p = strchr(p, ','))) {
593 mdefs->variant[i] = p;
598 if (p && (p = strchr(p, ',')))
606 FreeMultiDefs(struct multi_defs *defs)
609 free(UNCONSTIFY(defs->layout[1]));
610 free(UNCONSTIFY(defs->variant[1]));
614 Apply(char *src, char **dst)
617 if (*src == '+' || *src == '!') {
618 *dst= _Concat(*dst, src);
621 *dst= uDupString(src);
627 XkbRF_ApplyRule(struct rule *rule, struct xkb_component_names *names)
629 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
631 Apply(rule->keycodes, &names->keycodes);
632 Apply(rule->symbols, &names->symbols);
633 Apply(rule->types, &names->types);
634 Apply(rule->compat, &names->compat);
635 Apply(rule->keymap, &names->keymap);
639 CheckGroup(struct rules *rules, const char *group_name, const char *name)
645 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
646 if (! strcmp(group->name, group_name)) {
650 if (i == rules->num_groups)
652 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
653 if (! strcmp(p, name)) {
661 XkbRF_CheckApplyRule(struct rule *rule, struct multi_defs *mdefs,
662 struct xkb_component_names *names, struct rules *rules)
664 bool pending = false;
666 if (rule->model != NULL) {
667 if(mdefs->model == NULL)
669 if (strcmp(rule->model, "*") == 0) {
672 if (rule->model[0] == '$') {
673 if (!CheckGroup(rules, rule->model, mdefs->model))
676 if (strcmp(rule->model, mdefs->model) != 0)
681 if (rule->option != NULL) {
682 if (mdefs->options == NULL)
684 if ((!MatchOneOf(rule->option,mdefs->options)))
688 if (rule->layout != NULL) {
689 if(mdefs->layout[rule->layout_num] == NULL ||
690 *mdefs->layout[rule->layout_num] == '\0')
692 if (strcmp(rule->layout, "*") == 0) {
695 if (rule->layout[0] == '$') {
696 if (!CheckGroup(rules, rule->layout,
697 mdefs->layout[rule->layout_num]))
700 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
705 if (rule->variant != NULL) {
706 if (mdefs->variant[rule->variant_num] == NULL ||
707 *mdefs->variant[rule->variant_num] == '\0')
709 if (strcmp(rule->variant, "*") == 0) {
712 if (rule->variant[0] == '$') {
713 if (!CheckGroup(rules, rule->variant,
714 mdefs->variant[rule->variant_num]))
717 if (strcmp(rule->variant,
718 mdefs->variant[rule->variant_num]) != 0)
724 rule->flags|= XkbRF_PendingMatch;
727 /* exact match, apply it now */
728 XkbRF_ApplyRule(rule,names);
733 XkbRF_ClearPartialMatches(struct rules *rules)
738 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
739 rule->flags&= ~XkbRF_PendingMatch;
744 XkbRF_ApplyPartialMatches(struct rules *rules,
745 struct xkb_component_names *names)
750 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
751 if ((rule->flags&XkbRF_PendingMatch)==0)
753 XkbRF_ApplyRule(rule,names);
758 XkbRF_CheckApplyRules(struct rules *rules, struct multi_defs *mdefs,
759 struct xkb_component_names *names, unsigned int flags)
765 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
766 if ((rule->flags & flags) != flags)
768 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
769 if (skip && !(flags & XkbRF_Option)) {
770 for ( ;(i < rules->num_rules) && (rule->number == skip);
777 /***====================================================================***/
780 XkbRF_SubstituteVars(char *name, struct multi_defs *mdefs)
782 char *str, *outstr, *orig, *var;
790 str= strchr(name,'%');
797 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
806 str = get_index(var + 1, &ndx);
808 str = strchr(str,'%');
811 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
812 len+= strlen(mdefs->layout[ndx])+extra_len;
813 else if ((*var=='m')&&mdefs->model)
814 len+= strlen(mdefs->model)+extra_len;
815 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
816 len+= strlen(mdefs->variant[ndx])+extra_len;
817 if ((pfx=='(')&&(*str==')')) {
820 str= strchr(&str[0],'%');
822 name = malloc(len + 1);
831 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
841 str = get_index(var + 1, &ndx);
845 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
846 if (pfx) *outstr++= pfx;
847 strcpy(outstr,mdefs->layout[ndx]);
848 outstr+= strlen(mdefs->layout[ndx]);
849 if (sfx) *outstr++= sfx;
851 else if ((*var=='m')&&(mdefs->model)) {
852 if (pfx) *outstr++= pfx;
853 strcpy(outstr,mdefs->model);
854 outstr+= strlen(mdefs->model);
855 if (sfx) *outstr++= sfx;
857 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
858 if (pfx) *outstr++= pfx;
859 strcpy(outstr,mdefs->variant[ndx]);
860 outstr+= strlen(mdefs->variant[ndx]);
861 if (sfx) *outstr++= sfx;
863 if ((pfx=='(')&&(*str==')'))
876 /***====================================================================***/
879 XkbcRF_GetComponents(struct rules *rules, const struct var_defs *defs,
880 struct xkb_component_names *names)
882 struct multi_defs mdefs;
884 MakeMultiDefs(&mdefs, defs);
886 memset(names, 0, sizeof(struct xkb_component_names));
887 XkbRF_ClearPartialMatches(rules);
888 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
889 XkbRF_ApplyPartialMatches(rules, names);
890 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
891 XkbRF_ApplyPartialMatches(rules, names);
892 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
893 XkbRF_ApplyPartialMatches(rules, names);
895 names->keycodes = XkbRF_SubstituteVars(names->keycodes, &mdefs);
896 names->symbols = XkbRF_SubstituteVars(names->symbols, &mdefs);
897 names->types = XkbRF_SubstituteVars(names->types, &mdefs);
898 names->compat = XkbRF_SubstituteVars(names->compat, &mdefs);
899 names->keymap = XkbRF_SubstituteVars(names->keymap, &mdefs);
901 FreeMultiDefs(&mdefs);
902 return (names->keycodes && names->symbols && names->types &&
903 names->compat) || names->keymap;
907 XkbcRF_AddRule(struct rules *rules)
909 if (rules->sz_rules<1) {
912 rules->rules = calloc(rules->sz_rules, sizeof(*rules->rules));
914 else if (rules->num_rules>=rules->sz_rules) {
916 rules->rules = realloc(rules->rules,
917 rules->sz_rules * sizeof(*rules->rules));
920 rules->sz_rules= rules->num_rules= 0;
923 memset(&rules->rules[rules->num_rules], 0, sizeof(*rules->rules));
924 return &rules->rules[rules->num_rules++];
927 static struct group *
928 XkbcRF_AddGroup(struct rules *rules)
930 if (rules->sz_groups<1) {
931 rules->sz_groups= 16;
932 rules->num_groups= 0;
933 rules->groups = calloc(rules->sz_groups, sizeof(*rules->groups));
935 else if (rules->num_groups >= rules->sz_groups) {
936 rules->sz_groups *= 2;
937 rules->groups = realloc(rules->groups,
938 rules->sz_groups * sizeof(*rules->groups));
940 if (!rules->groups) {
941 rules->sz_groups= rules->num_groups= 0;
945 memset(&rules->groups[rules->num_groups], 0, sizeof(*rules->groups));
946 return &rules->groups[rules->num_groups++];
949 static struct rules *
950 XkbcRF_LoadRules(FILE *file)
952 struct input_line line;
953 struct remap_spec remap;
954 struct rule trule, *rule;
955 struct group tgroup, *group;
958 rules = calloc(1, sizeof(*rules));
962 memset(&remap, 0, sizeof(remap));
963 memset(&tgroup, 0, sizeof(tgroup));
964 input_line_init(&line);
966 while (input_line_get(file, &line)) {
967 if (CheckLine(&line,&remap,&trule,&tgroup)) {
969 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
971 memset(&tgroup, 0, sizeof(tgroup));
974 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
976 memset(&trule, 0, sizeof(trule));
982 input_line_deinit(&line);
987 XkbRF_ClearVarDescriptions(struct describe_vars *var)
991 for (i=0;i<var->num_desc;i++) {
992 free(var->desc[i].name);
993 free(var->desc[i].desc);
994 var->desc[i].name= var->desc[i].desc= NULL;
1001 XkbcRF_Free(struct rules *rules)
1005 struct group *group;
1009 XkbRF_ClearVarDescriptions(&rules->models);
1010 XkbRF_ClearVarDescriptions(&rules->layouts);
1011 XkbRF_ClearVarDescriptions(&rules->variants);
1012 XkbRF_ClearVarDescriptions(&rules->options);
1014 for (i=0, rule = rules->rules; i < rules->num_rules && rules; i++, rule++) {
1017 free(rule->variant);
1019 free(rule->keycodes);
1020 free(rule->symbols);
1027 for (i=0, group = rules->groups; i < rules->num_groups && group; i++, group++) {
1031 free(rules->groups);
1036 struct xkb_component_names *
1037 xkb_components_from_rules(struct xkb_context *ctx,
1038 const struct xkb_rule_names *rmlvo)
1043 struct rules *loaded;
1044 struct xkb_component_names *names = NULL;
1045 struct var_defs defs = {
1046 .model = rmlvo->model,
1047 .layout = rmlvo->layout,
1048 .variant = rmlvo->variant,
1049 .options = rmlvo->options,
1052 rulesFile = XkbFindFileInPath(ctx, rmlvo->rules, XkmRulesFile,
1055 ERROR("could not find \"%s\" rules in XKB path\n", rmlvo->rules);
1056 ERROR("%d include paths searched:\n",
1057 xkb_context_num_include_paths(ctx));
1058 for (i = 0; i < xkb_context_num_include_paths(ctx); i++)
1059 ERROR("\t%s\n", xkb_context_include_path_get(ctx, i));
1063 loaded = XkbcRF_LoadRules(rulesFile);
1065 ERROR("failed to load XKB rules \"%s\"\n", rulesPath);
1069 names = calloc(1, sizeof(*names));
1071 ERROR("failed to allocate XKB components\n");
1075 if (!XkbcRF_GetComponents(loaded, &defs, names)) {
1076 free(names->keymap);
1077 free(names->keycodes);
1079 free(names->compat);
1080 free(names->symbols);
1083 ERROR("no components returned from XKB rules \"%s\"\n", rulesPath);
1087 XkbcRF_Free(loaded);