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 ********************************************************/
34 #define PR_DEBUG(s) fprintf(stderr,s)
35 #define PR_DEBUG1(s,a) fprintf(stderr,s,a)
36 #define PR_DEBUG2(s,a,b) fprintf(stderr,s,a,b)
39 #define PR_DEBUG1(s,a)
40 #define PR_DEBUG2(s,a,b)
43 /***====================================================================***/
45 #define DFLT_LINE_SIZE 128
51 char buf[DFLT_LINE_SIZE];
56 InitInputLine(InputLine *line)
60 line->sz_line= DFLT_LINE_SIZE;
61 line->line= line->buf;
65 FreeInputLine(InputLine *line)
67 if (line->line!=line->buf)
71 line->sz_line= DFLT_LINE_SIZE;
72 line->line= line->buf;
76 InputLineAddChar(InputLine *line,int ch)
78 if (line->num_line>=line->sz_line) {
79 if (line->line==line->buf) {
80 line->line = malloc(line->sz_line * 2);
81 memcpy(line->line,line->buf,line->sz_line);
84 line->line = realloc(line->line, line->sz_line * 2);
88 line->line[line->num_line++]= ch;
92 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
93 (int)((l)->line[(l)->num_line++]= (c)):\
94 InputLineAddChar(l,c))
97 GetInputLine(FILE *file,InputLine *line,bool checkbang)
100 bool endOfFile,spacePending,slashPending,inComment;
103 while ((!endOfFile)&&(line->num_line==0)) {
104 spacePending= slashPending= inComment= false;
105 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
107 if ((ch=getc(file))==EOF)
127 else if (slashPending) {
136 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
141 if ((ch!='\n')&&(line->num_line>0))
150 if (checkbang && ch=='!') {
151 if (line->num_line!=0) {
152 PR_DEBUG("The '!' legal only at start of line\n");
153 PR_DEBUG("Line containing '!' ignored\n");
164 /* else line->num_line++;*/
166 if ((line->num_line==0)&&(endOfFile))
172 /***====================================================================***/
186 #define PART_MASK 0x000F
187 #define COMPONENT_MASK 0x03F0
189 static const char * cname[MAX_WORDS] = {
190 "model", "layout", "variant", "option",
191 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
194 typedef struct _RemapSpec {
203 typedef struct _FileSpec {
204 char * name[MAX_WORDS];
205 struct _FileSpec * pending;
210 const char * layout[XkbNumKbdGroups+1];
211 const char * variant[XkbNumKbdGroups+1];
213 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
215 #define NDX_BUFF_SIZE 4
217 /***====================================================================***/
220 get_index(char *str, int *ndx)
222 char ndx_buf[NDX_BUFF_SIZE];
230 end = strchr(str, ']');
235 if ( (end - str) >= NDX_BUFF_SIZE) {
239 strncpy(ndx_buf, str, end - str);
240 ndx_buf[end - str] = '\0';
241 *ndx = atoi(ndx_buf);
246 SetUpRemap(InputLine *line,RemapSpec *remap)
249 unsigned present, l_ndx_present, v_ndx_present;
259 l_ndx_present = v_ndx_present = present= 0;
262 memset(remap, 0, sizeof(RemapSpec));
264 while ((tok = strtok_r(str, " ", &strtok_buf)) != NULL) {
269 if (strcmp(tok,"=")==0)
271 for (i=0;i<MAX_WORDS;i++) {
272 len = strlen(cname[i]);
273 if (strncmp(cname[i],tok,len)==0) {
274 if(strlen(tok) > len) {
275 char *end = get_index(tok+len, &ndx);
276 if ((i != LAYOUT && i != VARIANT) ||
277 *end != '\0' || ndx == -1)
279 if (ndx < 1 || ndx > XkbNumKbdGroups) {
280 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
281 PR_DEBUG1("Index must be in range 1..%d\n",
291 if (present&(1<<i)) {
292 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
293 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
294 PR_DEBUG1("Component \"%s\" listed twice\n",tok);
295 PR_DEBUG("Second definition ignored\n");
301 l_ndx_present |= 1 << ndx;
303 v_ndx_present |= 1 << ndx;
304 remap->remap[remap->num_remap].word= i;
305 remap->remap[remap->num_remap++].index= ndx;
311 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
315 if ((present&PART_MASK)==0) {
317 unsigned mask= PART_MASK;
318 fprintf(stderr,"Mapping needs at least one of ");
319 for (i=0; (i<MAX_WORDS); i++) {
322 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
323 else fprintf(stderr,"or \"%s\"\n",cname[i]);
326 fprintf(stderr,"Illegal mapping ignored\n");
331 if ((present&COMPONENT_MASK)==0) {
332 PR_DEBUG("Mapping needs at least one component\n");
333 PR_DEBUG("Illegal mapping ignored\n");
337 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
338 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
339 PR_DEBUG("Keymap cannot appear with other components\n");
340 PR_DEBUG("Illegal mapping ignored\n");
348 MatchOneOf(char *wanted,char *vals_defined)
351 int want_len = strlen(wanted);
353 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
355 next= strchr(str,',');
363 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
369 /***====================================================================***/
372 CheckLine( InputLine * line,
375 XkbRF_GroupPtr group)
383 if (line->line[0]=='!') {
384 if (line->line[1] == '$' ||
385 (line->line[1] == ' ' && line->line[2] == '$')) {
386 char *gname = strchr(line->line, '$');
387 char *words = strchr(gname, ' ');
391 for (; *words; words++) {
392 if (*words != '=' && *words != ' ')
397 group->name = uDupString(gname);
398 group->words = uDupString(words);
399 for (i = 1, words = group->words; *words; words++) {
400 if ( *words == ' ') {
408 SetUpRemap(line,remap);
413 if (remap->num_remap==0) {
414 PR_DEBUG("Must have a mapping before first line of data\n");
415 PR_DEBUG("Illegal line of data ignored\n");
418 memset(&tmp, 0, sizeof(FileSpec));
420 for (nread = 0; (tok = strtok_r(str, " ", &strtok_buf)) != NULL; nread++) {
422 if (strcmp(tok,"=")==0) {
426 if (nread>remap->num_remap) {
427 PR_DEBUG("Too many words on a line\n");
428 PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
431 tmp.name[remap->remap[nread].word]= tok;
432 if (*tok == '+' || *tok == '|')
435 if (nread<remap->num_remap) {
436 PR_DEBUG1("Too few words on a line: %s\n", line->line);
437 PR_DEBUG("line ignored\n");
442 rule->number = remap->number;
443 if (tmp.name[OPTION])
444 rule->flags|= XkbRF_Option;
446 rule->flags|= XkbRF_Append;
448 rule->flags|= XkbRF_Normal;
449 rule->model= uDupString(tmp.name[MODEL]);
450 rule->layout= uDupString(tmp.name[LAYOUT]);
451 rule->variant= uDupString(tmp.name[VARIANT]);
452 rule->option= uDupString(tmp.name[OPTION]);
454 rule->keycodes= uDupString(tmp.name[KEYCODES]);
455 rule->symbols= uDupString(tmp.name[SYMBOLS]);
456 rule->types= uDupString(tmp.name[TYPES]);
457 rule->compat= uDupString(tmp.name[COMPAT]);
458 rule->keymap= uDupString(tmp.name[KEYMAP]);
460 rule->layout_num = rule->variant_num = 0;
461 for (i = 0; i < nread; i++) {
462 if (remap->remap[i].index) {
463 if (remap->remap[i].word == LAYOUT)
464 rule->layout_num = remap->remap[i].index;
465 if (remap->remap[i].word == VARIANT)
466 rule->variant_num = remap->remap[i].index;
473 _Concat(char *str1,char *str2)
477 if ((!str1)||(!str2))
479 len= strlen(str1)+strlen(str2)+1;
480 str1 = uTypedRealloc(str1, len, char);
487 squeeze_spaces(char *p1)
490 for (p2 = p1; *p2; p2++) {
492 if (*p1 != ' ') p1++;
498 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
500 memset(mdefs, 0, sizeof(XkbRF_MultiDefsRec));
501 mdefs->model = defs->model;
502 mdefs->options = uDupString(defs->options);
503 if (mdefs->options) squeeze_spaces(mdefs->options);
506 if (!strchr(defs->layout, ',')) {
507 mdefs->layout[0] = defs->layout;
511 p = uDupString(defs->layout);
515 mdefs->layout[1] = p;
516 for (i = 2; i <= XkbNumKbdGroups; i++) {
517 if ((p = strchr(p, ','))) {
519 mdefs->layout[i] = p;
524 if (p && (p = strchr(p, ',')))
530 if (!strchr(defs->variant, ',')) {
531 mdefs->variant[0] = defs->variant;
535 p = uDupString(defs->variant);
539 mdefs->variant[1] = p;
540 for (i = 2; i <= XkbNumKbdGroups; i++) {
541 if ((p = strchr(p, ','))) {
543 mdefs->variant[i] = p;
548 if (p && (p = strchr(p, ',')))
556 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
559 free(UNCONSTIFY(defs->layout[1]));
560 free(UNCONSTIFY(defs->variant[1]));
564 Apply(char *src, char **dst)
567 if (*src == '+' || *src == '!') {
568 *dst= _Concat(*dst, src);
571 *dst= uDupString(src);
577 XkbRF_ApplyRule( XkbRF_RulePtr rule,
578 struct xkb_component_names * names)
580 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
582 Apply(rule->keycodes, &names->keycodes);
583 Apply(rule->symbols, &names->symbols);
584 Apply(rule->types, &names->types);
585 Apply(rule->compat, &names->compat);
586 Apply(rule->keymap, &names->keymap);
590 CheckGroup( XkbRF_RulesPtr rules,
591 const char * group_name,
596 XkbRF_GroupPtr group;
598 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
599 if (! strcmp(group->name, group_name)) {
603 if (i == rules->num_groups)
605 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
606 if (! strcmp(p, name)) {
614 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
615 XkbRF_MultiDefsPtr mdefs,
616 struct xkb_component_names * names,
617 XkbRF_RulesPtr rules)
619 bool pending = false;
621 if (rule->model != NULL) {
622 if(mdefs->model == NULL)
624 if (strcmp(rule->model, "*") == 0) {
627 if (rule->model[0] == '$') {
628 if (!CheckGroup(rules, rule->model, mdefs->model))
631 if (strcmp(rule->model, mdefs->model) != 0)
636 if (rule->option != NULL) {
637 if (mdefs->options == NULL)
639 if ((!MatchOneOf(rule->option,mdefs->options)))
643 if (rule->layout != NULL) {
644 if(mdefs->layout[rule->layout_num] == NULL ||
645 *mdefs->layout[rule->layout_num] == '\0')
647 if (strcmp(rule->layout, "*") == 0) {
650 if (rule->layout[0] == '$') {
651 if (!CheckGroup(rules, rule->layout,
652 mdefs->layout[rule->layout_num]))
655 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
660 if (rule->variant != NULL) {
661 if (mdefs->variant[rule->variant_num] == NULL ||
662 *mdefs->variant[rule->variant_num] == '\0')
664 if (strcmp(rule->variant, "*") == 0) {
667 if (rule->variant[0] == '$') {
668 if (!CheckGroup(rules, rule->variant,
669 mdefs->variant[rule->variant_num]))
672 if (strcmp(rule->variant,
673 mdefs->variant[rule->variant_num]) != 0)
679 rule->flags|= XkbRF_PendingMatch;
682 /* exact match, apply it now */
683 XkbRF_ApplyRule(rule,names);
688 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
693 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
694 rule->flags&= ~XkbRF_PendingMatch;
699 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,struct xkb_component_names * names)
704 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
705 if ((rule->flags&XkbRF_PendingMatch)==0)
707 XkbRF_ApplyRule(rule,names);
712 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
713 XkbRF_MultiDefsPtr mdefs,
714 struct xkb_component_names * names,
721 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
722 if ((rule->flags & flags) != flags)
724 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
725 if (skip && !(flags & XkbRF_Option)) {
726 for ( ;(i < rules->num_rules) && (rule->number == skip);
733 /***====================================================================***/
736 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
738 char *str, *outstr, *orig, *var;
743 str= strchr(name,'%');
750 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
759 str = get_index(var + 1, &ndx);
761 str = strchr(str,'%');
764 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
765 len+= strlen(mdefs->layout[ndx])+extra_len;
766 else if ((*var=='m')&&mdefs->model)
767 len+= strlen(mdefs->model)+extra_len;
768 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
769 len+= strlen(mdefs->variant[ndx])+extra_len;
770 if ((pfx=='(')&&(*str==')')) {
773 str= strchr(&str[0],'%');
775 name = malloc(len + 1);
784 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
794 str = get_index(var + 1, &ndx);
798 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
799 if (pfx) *outstr++= pfx;
800 strcpy(outstr,mdefs->layout[ndx]);
801 outstr+= strlen(mdefs->layout[ndx]);
802 if (sfx) *outstr++= sfx;
804 else if ((*var=='m')&&(mdefs->model)) {
805 if (pfx) *outstr++= pfx;
806 strcpy(outstr,mdefs->model);
807 outstr+= strlen(mdefs->model);
808 if (sfx) *outstr++= sfx;
810 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
811 if (pfx) *outstr++= pfx;
812 strcpy(outstr,mdefs->variant[ndx]);
813 outstr+= strlen(mdefs->variant[ndx]);
814 if (sfx) *outstr++= sfx;
816 if ((pfx=='(')&&(*str==')'))
829 /***====================================================================***/
832 XkbcRF_GetComponents( XkbRF_RulesPtr rules,
833 XkbRF_VarDefsPtr defs,
834 struct xkb_component_names * names)
836 XkbRF_MultiDefsRec mdefs;
838 MakeMultiDefs(&mdefs, defs);
840 memset(names, 0, sizeof(struct xkb_component_names));
841 XkbRF_ClearPartialMatches(rules);
842 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
843 XkbRF_ApplyPartialMatches(rules, names);
844 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
845 XkbRF_ApplyPartialMatches(rules, names);
846 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
847 XkbRF_ApplyPartialMatches(rules, names);
850 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
852 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
854 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
856 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
858 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
860 FreeMultiDefs(&mdefs);
861 return (names->keycodes && names->symbols && names->types &&
862 names->compat) || names->keymap;
866 XkbcRF_AddRule(XkbRF_RulesPtr rules)
868 if (rules->sz_rules<1) {
871 rules->rules= uTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
873 else if (rules->num_rules>=rules->sz_rules) {
875 rules->rules= uTypedRealloc(rules->rules,rules->sz_rules,
879 rules->sz_rules= rules->num_rules= 0;
881 fprintf(stderr,"Allocation failure in XkbcRF_AddRule\n");
885 memset(&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
886 return &rules->rules[rules->num_rules++];
889 static XkbRF_GroupPtr
890 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
892 if (rules->sz_groups<1) {
893 rules->sz_groups= 16;
894 rules->num_groups= 0;
895 rules->groups= uTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
897 else if (rules->num_groups >= rules->sz_groups) {
898 rules->sz_groups *= 2;
899 rules->groups= uTypedRealloc(rules->groups,rules->sz_groups,
902 if (!rules->groups) {
903 rules->sz_groups= rules->num_groups= 0;
907 memset(&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec));
908 return &rules->groups[rules->num_groups++];
912 XkbcRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
916 XkbRF_RuleRec trule,*rule;
917 XkbRF_GroupRec tgroup,*group;
919 if (!(rules && file))
921 memset(&remap, 0, sizeof(RemapSpec));
922 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
923 InitInputLine(&line);
924 while (GetInputLine(file, &line, true)) {
925 if (CheckLine(&line,&remap,&trule,&tgroup)) {
927 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
929 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
932 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
934 memset(&trule, 0, sizeof(XkbRF_RuleRec));
940 FreeInputLine(&line);
945 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
949 for (i=0;i<var->num_desc;i++) {
950 free(var->desc[i].name);
951 free(var->desc[i].desc);
952 var->desc[i].name= var->desc[i].desc= NULL;
959 XkbcRF_Free(XkbRF_RulesPtr rules)
963 XkbRF_GroupPtr group;
967 XkbRF_ClearVarDescriptions(&rules->models);
968 XkbRF_ClearVarDescriptions(&rules->layouts);
969 XkbRF_ClearVarDescriptions(&rules->variants);
970 XkbRF_ClearVarDescriptions(&rules->options);
972 for (i = 0; i < rules->num_extra; i++) {
973 XkbRF_ClearVarDescriptions(&rules->extra[i]);
977 for (i=0, rule = rules->rules; i < rules->num_rules && rules; i++, rule++) {
982 free(rule->keycodes);
990 for (i=0, group = rules->groups; i < rules->num_groups && group; i++, group++) {