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 InitInputLine(InputLine *line)
46 line->sz_line= DFLT_LINE_SIZE;
47 line->line= line->buf;
51 FreeInputLine(InputLine *line)
53 if (line->line!=line->buf)
56 line->sz_line= DFLT_LINE_SIZE;
57 line->line= line->buf;
61 InputLineAddChar(InputLine *line,int ch)
63 if (line->num_line>=line->sz_line) {
64 if (line->line==line->buf) {
65 line->line = malloc(line->sz_line * 2);
66 memcpy(line->line,line->buf,line->sz_line);
69 line->line = realloc(line->line, line->sz_line * 2);
73 line->line[line->num_line++]= ch;
77 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
78 (int)((l)->line[(l)->num_line++]= (c)):\
79 InputLineAddChar(l,c))
82 GetInputLine(FILE *file,InputLine *line,bool checkbang)
85 bool endOfFile,spacePending,slashPending,inComment;
88 while ((!endOfFile)&&(line->num_line==0)) {
89 spacePending= slashPending= inComment= false;
90 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
92 if ((ch=getc(file))==EOF)
111 else if (slashPending) {
120 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
125 if ((ch!='\n')&&(line->num_line>0))
134 if (checkbang && ch=='!') {
135 if (line->num_line!=0) {
136 WARN("The '!' legal only at start of line\n");
137 ACTION("Line containing '!' ignored\n");
148 /* else line->num_line++;*/
150 if ((line->num_line==0)&&(endOfFile))
156 /***====================================================================***/
170 #define PART_MASK 0x000F
171 #define COMPONENT_MASK 0x03F0
173 static const char * cname[MAX_WORDS] = {
174 "model", "layout", "variant", "option",
175 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
183 } XkbRF_VarDefsRec, *XkbRF_VarDefsPtr;
185 typedef struct _RemapSpec {
194 typedef struct _FileSpec {
195 char * name[MAX_WORDS];
196 struct _FileSpec * pending;
201 const char * layout[XkbNumKbdGroups+1];
202 const char * variant[XkbNumKbdGroups+1];
204 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
206 typedef struct _XkbRF_VarDesc {
209 } XkbRF_VarDescRec, *XkbRF_VarDescPtr;
211 typedef struct _XkbRF_DescribeVars {
214 XkbRF_VarDescPtr desc;
215 } XkbRF_DescribeVarsRec,*XkbRF_DescribeVarsPtr;
217 typedef struct _XkbRF_Group {
221 } XkbRF_GroupRec, *XkbRF_GroupPtr;
223 #define XkbRF_PendingMatch (1L<<1)
224 #define XkbRF_Option (1L<<2)
225 #define XkbRF_Append (1L<<3)
226 #define XkbRF_Normal (1L<<4)
227 #define XkbRF_Invalid (1L<<5)
229 typedef struct _XkbRF_Rule {
244 } XkbRF_RuleRec,*XkbRF_RulePtr;
246 typedef struct XkbRF_Rules {
247 XkbRF_DescribeVarsRec models;
248 XkbRF_DescribeVarsRec layouts;
249 XkbRF_DescribeVarsRec variants;
250 XkbRF_DescribeVarsRec options;
257 XkbRF_GroupPtr groups;
258 } XkbRF_RulesRec, *XkbRF_RulesPtr;
260 #define NDX_BUFF_SIZE 4
262 /***====================================================================***/
265 get_index(char *str, int *ndx)
267 char ndx_buf[NDX_BUFF_SIZE];
275 end = strchr(str, ']');
280 if ( (end - str) >= NDX_BUFF_SIZE) {
284 strncpy(ndx_buf, str, end - str);
285 ndx_buf[end - str] = '\0';
286 *ndx = atoi(ndx_buf);
291 SetUpRemap(InputLine *line,RemapSpec *remap)
294 unsigned present, l_ndx_present, v_ndx_present;
301 l_ndx_present = v_ndx_present = present= 0;
304 memset(remap, 0, sizeof(RemapSpec));
306 while ((tok = strtok_r(str, " ", &strtok_buf)) != NULL) {
309 if (strcmp(tok,"=")==0)
311 for (i=0;i<MAX_WORDS;i++) {
312 len = strlen(cname[i]);
313 if (strncmp(cname[i],tok,len)==0) {
314 if(strlen(tok) > len) {
315 char *end = get_index(tok+len, &ndx);
316 if ((i != LAYOUT && i != VARIANT) ||
317 *end != '\0' || ndx == -1)
319 if (ndx < 1 || ndx > XkbNumKbdGroups) {
320 WARN("Illegal %s index: %d\n", cname[i], ndx);
321 WARN("Index must be in range 1..%d\n", XkbNumKbdGroups);
330 if (present&(1<<i)) {
331 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
332 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
333 WARN("Component \"%s\" listed twice\n", tok);
334 ACTION("Second definition ignored\n");
340 l_ndx_present |= 1 << ndx;
342 v_ndx_present |= 1 << ndx;
343 remap->remap[remap->num_remap].word= i;
344 remap->remap[remap->num_remap++].index= ndx;
350 WARN("Unknown component \"%s\"\n", tok);
354 if ((present&PART_MASK)==0) {
355 unsigned mask= PART_MASK;
357 /* FIXME: Use log function instead of fprintf. */
358 WARN("Mapping needs at least one of ");
359 for (i=0; (i<MAX_WORDS); i++) {
362 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
363 else fprintf(stderr,"or \"%s\"\n",cname[i]);
366 ACTION("Illegal mapping ignored\n");
371 if ((present&COMPONENT_MASK)==0) {
372 WARN("Mapping needs at least one component\n");
373 ACTION("Illegal mapping ignored\n");
377 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
378 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
379 WARN("Keymap cannot appear with other components\n");
380 ACTION("Illegal mapping ignored\n");
388 MatchOneOf(char *wanted,char *vals_defined)
391 int want_len = strlen(wanted);
393 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
395 next= strchr(str,',');
403 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
409 /***====================================================================***/
412 CheckLine( InputLine * line,
415 XkbRF_GroupPtr group)
423 if (line->line[0]=='!') {
424 if (line->line[1] == '$' ||
425 (line->line[1] == ' ' && line->line[2] == '$')) {
426 char *gname = strchr(line->line, '$');
427 char *words = strchr(gname, ' ');
431 for (; *words; words++) {
432 if (*words != '=' && *words != ' ')
437 group->name = uDupString(gname);
438 group->words = uDupString(words);
439 for (i = 1, words = group->words; *words; words++) {
440 if ( *words == ' ') {
448 SetUpRemap(line,remap);
453 if (remap->num_remap==0) {
454 WARN("Must have a mapping before first line of data\n");
455 ACTION("Illegal line of data ignored\n");
458 memset(&tmp, 0, sizeof(FileSpec));
460 for (nread = 0; (tok = strtok_r(str, " ", &strtok_buf)) != NULL; nread++) {
462 if (strcmp(tok,"=")==0) {
466 if (nread>remap->num_remap) {
467 WARN("Too many words on a line\n");
468 ACTION("Extra word \"%s\" ignored\n",tok);
471 tmp.name[remap->remap[nread].word]= tok;
472 if (*tok == '+' || *tok == '|')
475 if (nread<remap->num_remap) {
476 WARN("Too few words on a line: %s\n", line->line);
477 ACTION("line ignored\n");
482 rule->number = remap->number;
483 if (tmp.name[OPTION])
484 rule->flags|= XkbRF_Option;
486 rule->flags|= XkbRF_Append;
488 rule->flags|= XkbRF_Normal;
489 rule->model= uDupString(tmp.name[MODEL]);
490 rule->layout= uDupString(tmp.name[LAYOUT]);
491 rule->variant= uDupString(tmp.name[VARIANT]);
492 rule->option= uDupString(tmp.name[OPTION]);
494 rule->keycodes= uDupString(tmp.name[KEYCODES]);
495 rule->symbols= uDupString(tmp.name[SYMBOLS]);
496 rule->types= uDupString(tmp.name[TYPES]);
497 rule->compat= uDupString(tmp.name[COMPAT]);
498 rule->keymap= uDupString(tmp.name[KEYMAP]);
500 rule->layout_num = rule->variant_num = 0;
501 for (i = 0; i < nread; i++) {
502 if (remap->remap[i].index) {
503 if (remap->remap[i].word == LAYOUT)
504 rule->layout_num = remap->remap[i].index;
505 if (remap->remap[i].word == VARIANT)
506 rule->variant_num = remap->remap[i].index;
513 _Concat(char *str1,char *str2)
517 if ((!str1)||(!str2))
519 len= strlen(str1)+strlen(str2)+1;
520 str1 = uTypedRealloc(str1, len, char);
527 squeeze_spaces(char *p1)
530 for (p2 = p1; *p2; p2++) {
532 if (*p1 != ' ') p1++;
538 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, const XkbRF_VarDefsPtr defs)
540 memset(mdefs, 0, sizeof(XkbRF_MultiDefsRec));
541 mdefs->model = defs->model;
542 mdefs->options = uDupString(defs->options);
543 if (mdefs->options) squeeze_spaces(mdefs->options);
546 if (!strchr(defs->layout, ',')) {
547 mdefs->layout[0] = defs->layout;
551 p = uDupString(defs->layout);
555 mdefs->layout[1] = p;
556 for (i = 2; i <= XkbNumKbdGroups; i++) {
557 if ((p = strchr(p, ','))) {
559 mdefs->layout[i] = p;
564 if (p && (p = strchr(p, ',')))
570 if (!strchr(defs->variant, ',')) {
571 mdefs->variant[0] = defs->variant;
575 p = uDupString(defs->variant);
579 mdefs->variant[1] = p;
580 for (i = 2; i <= XkbNumKbdGroups; i++) {
581 if ((p = strchr(p, ','))) {
583 mdefs->variant[i] = p;
588 if (p && (p = strchr(p, ',')))
596 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
599 free(UNCONSTIFY(defs->layout[1]));
600 free(UNCONSTIFY(defs->variant[1]));
604 Apply(char *src, char **dst)
607 if (*src == '+' || *src == '!') {
608 *dst= _Concat(*dst, src);
611 *dst= uDupString(src);
617 XkbRF_ApplyRule( XkbRF_RulePtr rule,
618 struct xkb_component_names * names)
620 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
622 Apply(rule->keycodes, &names->keycodes);
623 Apply(rule->symbols, &names->symbols);
624 Apply(rule->types, &names->types);
625 Apply(rule->compat, &names->compat);
626 Apply(rule->keymap, &names->keymap);
630 CheckGroup( XkbRF_RulesPtr rules,
631 const char * group_name,
636 XkbRF_GroupPtr group;
638 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
639 if (! strcmp(group->name, group_name)) {
643 if (i == rules->num_groups)
645 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
646 if (! strcmp(p, name)) {
654 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
655 XkbRF_MultiDefsPtr mdefs,
656 struct xkb_component_names * names,
657 XkbRF_RulesPtr rules)
659 bool pending = false;
661 if (rule->model != NULL) {
662 if(mdefs->model == NULL)
664 if (strcmp(rule->model, "*") == 0) {
667 if (rule->model[0] == '$') {
668 if (!CheckGroup(rules, rule->model, mdefs->model))
671 if (strcmp(rule->model, mdefs->model) != 0)
676 if (rule->option != NULL) {
677 if (mdefs->options == NULL)
679 if ((!MatchOneOf(rule->option,mdefs->options)))
683 if (rule->layout != NULL) {
684 if(mdefs->layout[rule->layout_num] == NULL ||
685 *mdefs->layout[rule->layout_num] == '\0')
687 if (strcmp(rule->layout, "*") == 0) {
690 if (rule->layout[0] == '$') {
691 if (!CheckGroup(rules, rule->layout,
692 mdefs->layout[rule->layout_num]))
695 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
700 if (rule->variant != NULL) {
701 if (mdefs->variant[rule->variant_num] == NULL ||
702 *mdefs->variant[rule->variant_num] == '\0')
704 if (strcmp(rule->variant, "*") == 0) {
707 if (rule->variant[0] == '$') {
708 if (!CheckGroup(rules, rule->variant,
709 mdefs->variant[rule->variant_num]))
712 if (strcmp(rule->variant,
713 mdefs->variant[rule->variant_num]) != 0)
719 rule->flags|= XkbRF_PendingMatch;
722 /* exact match, apply it now */
723 XkbRF_ApplyRule(rule,names);
728 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
733 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
734 rule->flags&= ~XkbRF_PendingMatch;
739 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,struct xkb_component_names * names)
744 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
745 if ((rule->flags&XkbRF_PendingMatch)==0)
747 XkbRF_ApplyRule(rule,names);
752 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
753 XkbRF_MultiDefsPtr mdefs,
754 struct xkb_component_names * names,
761 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
762 if ((rule->flags & flags) != flags)
764 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
765 if (skip && !(flags & XkbRF_Option)) {
766 for ( ;(i < rules->num_rules) && (rule->number == skip);
773 /***====================================================================***/
776 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
778 char *str, *outstr, *orig, *var;
786 str= strchr(name,'%');
793 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
802 str = get_index(var + 1, &ndx);
804 str = strchr(str,'%');
807 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
808 len+= strlen(mdefs->layout[ndx])+extra_len;
809 else if ((*var=='m')&&mdefs->model)
810 len+= strlen(mdefs->model)+extra_len;
811 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
812 len+= strlen(mdefs->variant[ndx])+extra_len;
813 if ((pfx=='(')&&(*str==')')) {
816 str= strchr(&str[0],'%');
818 name = malloc(len + 1);
827 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
837 str = get_index(var + 1, &ndx);
841 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
842 if (pfx) *outstr++= pfx;
843 strcpy(outstr,mdefs->layout[ndx]);
844 outstr+= strlen(mdefs->layout[ndx]);
845 if (sfx) *outstr++= sfx;
847 else if ((*var=='m')&&(mdefs->model)) {
848 if (pfx) *outstr++= pfx;
849 strcpy(outstr,mdefs->model);
850 outstr+= strlen(mdefs->model);
851 if (sfx) *outstr++= sfx;
853 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
854 if (pfx) *outstr++= pfx;
855 strcpy(outstr,mdefs->variant[ndx]);
856 outstr+= strlen(mdefs->variant[ndx]);
857 if (sfx) *outstr++= sfx;
859 if ((pfx=='(')&&(*str==')'))
872 /***====================================================================***/
875 XkbcRF_GetComponents(struct XkbRF_Rules *rules, const XkbRF_VarDefsPtr defs,
876 struct xkb_component_names *names)
878 XkbRF_MultiDefsRec mdefs;
880 MakeMultiDefs(&mdefs, defs);
882 memset(names, 0, sizeof(struct xkb_component_names));
883 XkbRF_ClearPartialMatches(rules);
884 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
885 XkbRF_ApplyPartialMatches(rules, names);
886 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
887 XkbRF_ApplyPartialMatches(rules, names);
888 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
889 XkbRF_ApplyPartialMatches(rules, names);
891 names->keycodes = XkbRF_SubstituteVars(names->keycodes, &mdefs);
892 names->symbols = XkbRF_SubstituteVars(names->symbols, &mdefs);
893 names->types = XkbRF_SubstituteVars(names->types, &mdefs);
894 names->compat = XkbRF_SubstituteVars(names->compat, &mdefs);
895 names->keymap = XkbRF_SubstituteVars(names->keymap, &mdefs);
897 FreeMultiDefs(&mdefs);
898 return (names->keycodes && names->symbols && names->types &&
899 names->compat) || names->keymap;
903 XkbcRF_AddRule(XkbRF_RulesPtr rules)
905 if (rules->sz_rules<1) {
908 rules->rules= uTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
910 else if (rules->num_rules>=rules->sz_rules) {
912 rules->rules= uTypedRealloc(rules->rules,rules->sz_rules,
916 rules->sz_rules= rules->num_rules= 0;
919 memset(&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
920 return &rules->rules[rules->num_rules++];
923 static XkbRF_GroupPtr
924 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
926 if (rules->sz_groups<1) {
927 rules->sz_groups= 16;
928 rules->num_groups= 0;
929 rules->groups= uTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
931 else if (rules->num_groups >= rules->sz_groups) {
932 rules->sz_groups *= 2;
933 rules->groups= uTypedRealloc(rules->groups,rules->sz_groups,
936 if (!rules->groups) {
937 rules->sz_groups= rules->num_groups= 0;
941 memset(&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec));
942 return &rules->groups[rules->num_groups++];
945 static XkbRF_RulesPtr
946 XkbcRF_LoadRules(FILE *file)
950 XkbRF_RuleRec trule,*rule;
951 XkbRF_GroupRec tgroup,*group;
952 XkbRF_RulesPtr rules;
954 rules = calloc(1, sizeof(*rules));
958 memset(&remap, 0, sizeof(RemapSpec));
959 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
960 InitInputLine(&line);
961 while (GetInputLine(file, &line, true)) {
962 if (CheckLine(&line,&remap,&trule,&tgroup)) {
964 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
966 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
969 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
971 memset(&trule, 0, sizeof(XkbRF_RuleRec));
977 FreeInputLine(&line);
982 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
986 for (i=0;i<var->num_desc;i++) {
987 free(var->desc[i].name);
988 free(var->desc[i].desc);
989 var->desc[i].name= var->desc[i].desc= NULL;
996 XkbcRF_Free(XkbRF_RulesPtr rules)
1000 XkbRF_GroupPtr group;
1004 XkbRF_ClearVarDescriptions(&rules->models);
1005 XkbRF_ClearVarDescriptions(&rules->layouts);
1006 XkbRF_ClearVarDescriptions(&rules->variants);
1007 XkbRF_ClearVarDescriptions(&rules->options);
1009 for (i=0, rule = rules->rules; i < rules->num_rules && rules; i++, rule++) {
1012 free(rule->variant);
1014 free(rule->keycodes);
1015 free(rule->symbols);
1022 for (i=0, group = rules->groups; i < rules->num_groups && group; i++, group++) {
1026 free(rules->groups);
1031 struct xkb_component_names *
1032 xkb_components_from_rules(struct xkb_context *ctx,
1033 const struct xkb_rule_names *rmlvo)
1038 XkbRF_RulesPtr loaded;
1039 struct xkb_component_names *names = NULL;
1040 XkbRF_VarDefsRec defs = {
1041 .model = rmlvo->model,
1042 .layout = rmlvo->layout,
1043 .variant = rmlvo->variant,
1044 .options = rmlvo->options,
1047 rulesFile = XkbFindFileInPath(ctx, rmlvo->rules, XkmRulesFile,
1050 ERROR("could not find \"%s\" rules in XKB path\n", rmlvo->rules);
1051 ERROR("%d include paths searched:\n",
1052 xkb_context_num_include_paths(ctx));
1053 for (i = 0; i < xkb_context_num_include_paths(ctx); i++)
1054 ERROR("\t%s\n", xkb_context_include_path_get(ctx, i));
1058 loaded = XkbcRF_LoadRules(rulesFile);
1060 ERROR("failed to load XKB rules \"%s\"\n", rulesPath);
1064 names = calloc(1, sizeof(*names));
1066 ERROR("failed to allocate XKB components\n");
1070 if (!XkbcRF_GetComponents(loaded, &defs, names)) {
1071 free(names->keymap);
1072 free(names->keycodes);
1074 free(names->compat);
1075 free(names->symbols);
1078 ERROR("no components returned from XKB rules \"%s\"\n", rulesPath);
1082 XkbcRF_Free(loaded);