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 PR_DEBUG(s) fprintf(stderr,s)
34 #define PR_DEBUG1(s,a) fprintf(stderr,s,a)
35 #define PR_DEBUG2(s,a,b) fprintf(stderr,s,a,b)
38 #define PR_DEBUG1(s,a)
39 #define PR_DEBUG2(s,a,b)
42 /***====================================================================***/
44 #define DFLT_LINE_SIZE 128
50 char buf[DFLT_LINE_SIZE];
55 InitInputLine(InputLine *line)
59 line->sz_line= DFLT_LINE_SIZE;
60 line->line= line->buf;
64 FreeInputLine(InputLine *line)
66 if (line->line!=line->buf)
70 line->sz_line= DFLT_LINE_SIZE;
71 line->line= line->buf;
75 InputLineAddChar(InputLine *line,int ch)
77 if (line->num_line>=line->sz_line) {
78 if (line->line==line->buf) {
79 line->line = malloc(line->sz_line * 2);
80 memcpy(line->line,line->buf,line->sz_line);
83 line->line = realloc(line->line, line->sz_line * 2);
87 line->line[line->num_line++]= ch;
91 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
92 (int)((l)->line[(l)->num_line++]= (c)):\
93 InputLineAddChar(l,c))
96 GetInputLine(FILE *file,InputLine *line,bool checkbang)
99 bool endOfFile,spacePending,slashPending,inComment;
102 while ((!endOfFile)&&(line->num_line==0)) {
103 spacePending= slashPending= inComment= false;
104 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
106 if ((ch=getc(file))==EOF)
126 else if (slashPending) {
135 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
140 if ((ch!='\n')&&(line->num_line>0))
149 if (checkbang && ch=='!') {
150 if (line->num_line!=0) {
151 PR_DEBUG("The '!' legal only at start of line\n");
152 PR_DEBUG("Line containing '!' ignored\n");
163 /* else line->num_line++;*/
165 if ((line->num_line==0)&&(endOfFile))
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"
193 typedef struct _RemapSpec {
202 typedef struct _FileSpec {
203 char * name[MAX_WORDS];
204 struct _FileSpec * pending;
209 const char * layout[XkbNumKbdGroups+1];
210 const char * variant[XkbNumKbdGroups+1];
212 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
214 #define NDX_BUFF_SIZE 4
216 /***====================================================================***/
219 get_index(char *str, int *ndx)
221 char ndx_buf[NDX_BUFF_SIZE];
229 end = strchr(str, ']');
234 if ( (end - str) >= NDX_BUFF_SIZE) {
238 strncpy(ndx_buf, str, end - str);
239 ndx_buf[end - str] = '\0';
240 *ndx = atoi(ndx_buf);
245 SetUpRemap(InputLine *line,RemapSpec *remap)
248 unsigned present, l_ndx_present, v_ndx_present;
258 l_ndx_present = v_ndx_present = present= 0;
261 memset(remap, 0, sizeof(RemapSpec));
263 while ((tok = strtok_r(str, " ", &strtok_buf)) != NULL) {
268 if (strcmp(tok,"=")==0)
270 for (i=0;i<MAX_WORDS;i++) {
271 len = strlen(cname[i]);
272 if (strncmp(cname[i],tok,len)==0) {
273 if(strlen(tok) > len) {
274 char *end = get_index(tok+len, &ndx);
275 if ((i != LAYOUT && i != VARIANT) ||
276 *end != '\0' || ndx == -1)
278 if (ndx < 1 || ndx > XkbNumKbdGroups) {
279 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
280 PR_DEBUG1("Index must be in range 1..%d\n",
290 if (present&(1<<i)) {
291 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
292 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
293 PR_DEBUG1("Component \"%s\" listed twice\n",tok);
294 PR_DEBUG("Second definition ignored\n");
300 l_ndx_present |= 1 << ndx;
302 v_ndx_present |= 1 << ndx;
303 remap->remap[remap->num_remap].word= i;
304 remap->remap[remap->num_remap++].index= ndx;
310 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
314 if ((present&PART_MASK)==0) {
316 unsigned mask= PART_MASK;
317 fprintf(stderr,"Mapping needs at least one of ");
318 for (i=0; (i<MAX_WORDS); i++) {
321 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
322 else fprintf(stderr,"or \"%s\"\n",cname[i]);
325 fprintf(stderr,"Illegal mapping ignored\n");
330 if ((present&COMPONENT_MASK)==0) {
331 PR_DEBUG("Mapping needs at least one component\n");
332 PR_DEBUG("Illegal mapping ignored\n");
336 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
337 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
338 PR_DEBUG("Keymap cannot appear with other components\n");
339 PR_DEBUG("Illegal mapping ignored\n");
347 MatchOneOf(char *wanted,char *vals_defined)
350 int want_len = strlen(wanted);
352 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
354 next= strchr(str,',');
362 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
368 /***====================================================================***/
371 CheckLine( InputLine * line,
374 XkbRF_GroupPtr group)
382 if (line->line[0]=='!') {
383 if (line->line[1] == '$' ||
384 (line->line[1] == ' ' && line->line[2] == '$')) {
385 char *gname = strchr(line->line, '$');
386 char *words = strchr(gname, ' ');
390 for (; *words; words++) {
391 if (*words != '=' && *words != ' ')
396 group->name = uDupString(gname);
397 group->words = uDupString(words);
398 for (i = 1, words = group->words; *words; words++) {
399 if ( *words == ' ') {
407 SetUpRemap(line,remap);
412 if (remap->num_remap==0) {
413 PR_DEBUG("Must have a mapping before first line of data\n");
414 PR_DEBUG("Illegal line of data ignored\n");
417 memset(&tmp, 0, sizeof(FileSpec));
419 for (nread = 0; (tok = strtok_r(str, " ", &strtok_buf)) != NULL; nread++) {
421 if (strcmp(tok,"=")==0) {
425 if (nread>remap->num_remap) {
426 PR_DEBUG("Too many words on a line\n");
427 PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
430 tmp.name[remap->remap[nread].word]= tok;
431 if (*tok == '+' || *tok == '|')
434 if (nread<remap->num_remap) {
435 PR_DEBUG1("Too few words on a line: %s\n", line->line);
436 PR_DEBUG("line ignored\n");
441 rule->number = remap->number;
442 if (tmp.name[OPTION])
443 rule->flags|= XkbRF_Option;
445 rule->flags|= XkbRF_Append;
447 rule->flags|= XkbRF_Normal;
448 rule->model= uDupString(tmp.name[MODEL]);
449 rule->layout= uDupString(tmp.name[LAYOUT]);
450 rule->variant= uDupString(tmp.name[VARIANT]);
451 rule->option= uDupString(tmp.name[OPTION]);
453 rule->keycodes= uDupString(tmp.name[KEYCODES]);
454 rule->symbols= uDupString(tmp.name[SYMBOLS]);
455 rule->types= uDupString(tmp.name[TYPES]);
456 rule->compat= uDupString(tmp.name[COMPAT]);
457 rule->keymap= uDupString(tmp.name[KEYMAP]);
459 rule->layout_num = rule->variant_num = 0;
460 for (i = 0; i < nread; i++) {
461 if (remap->remap[i].index) {
462 if (remap->remap[i].word == LAYOUT)
463 rule->layout_num = remap->remap[i].index;
464 if (remap->remap[i].word == VARIANT)
465 rule->variant_num = remap->remap[i].index;
472 _Concat(char *str1,char *str2)
476 if ((!str1)||(!str2))
478 len= strlen(str1)+strlen(str2)+1;
479 str1 = uTypedRealloc(str1, len, char);
486 squeeze_spaces(char *p1)
489 for (p2 = p1; *p2; p2++) {
491 if (*p1 != ' ') p1++;
497 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
499 memset(mdefs, 0, sizeof(XkbRF_MultiDefsRec));
500 mdefs->model = defs->model;
501 mdefs->options = uDupString(defs->options);
502 if (mdefs->options) squeeze_spaces(mdefs->options);
505 if (!strchr(defs->layout, ',')) {
506 mdefs->layout[0] = defs->layout;
510 p = uDupString(defs->layout);
514 mdefs->layout[1] = p;
515 for (i = 2; i <= XkbNumKbdGroups; i++) {
516 if ((p = strchr(p, ','))) {
518 mdefs->layout[i] = p;
523 if (p && (p = strchr(p, ',')))
529 if (!strchr(defs->variant, ',')) {
530 mdefs->variant[0] = defs->variant;
534 p = uDupString(defs->variant);
538 mdefs->variant[1] = p;
539 for (i = 2; i <= XkbNumKbdGroups; i++) {
540 if ((p = strchr(p, ','))) {
542 mdefs->variant[i] = p;
547 if (p && (p = strchr(p, ',')))
555 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
558 free(UNCONSTIFY(defs->layout[1]));
559 free(UNCONSTIFY(defs->variant[1]));
563 Apply(char *src, char **dst)
566 if (*src == '+' || *src == '!') {
567 *dst= _Concat(*dst, src);
570 *dst= uDupString(src);
576 XkbRF_ApplyRule( XkbRF_RulePtr rule,
577 struct xkb_component_names * names)
579 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
581 Apply(rule->keycodes, &names->keycodes);
582 Apply(rule->symbols, &names->symbols);
583 Apply(rule->types, &names->types);
584 Apply(rule->compat, &names->compat);
585 Apply(rule->keymap, &names->keymap);
589 CheckGroup( XkbRF_RulesPtr rules,
590 const char * group_name,
595 XkbRF_GroupPtr group;
597 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
598 if (! strcmp(group->name, group_name)) {
602 if (i == rules->num_groups)
604 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
605 if (! strcmp(p, name)) {
613 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
614 XkbRF_MultiDefsPtr mdefs,
615 struct xkb_component_names * names,
616 XkbRF_RulesPtr rules)
618 bool pending = false;
620 if (rule->model != NULL) {
621 if(mdefs->model == NULL)
623 if (strcmp(rule->model, "*") == 0) {
626 if (rule->model[0] == '$') {
627 if (!CheckGroup(rules, rule->model, mdefs->model))
630 if (strcmp(rule->model, mdefs->model) != 0)
635 if (rule->option != NULL) {
636 if (mdefs->options == NULL)
638 if ((!MatchOneOf(rule->option,mdefs->options)))
642 if (rule->layout != NULL) {
643 if(mdefs->layout[rule->layout_num] == NULL ||
644 *mdefs->layout[rule->layout_num] == '\0')
646 if (strcmp(rule->layout, "*") == 0) {
649 if (rule->layout[0] == '$') {
650 if (!CheckGroup(rules, rule->layout,
651 mdefs->layout[rule->layout_num]))
654 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
659 if (rule->variant != NULL) {
660 if (mdefs->variant[rule->variant_num] == NULL ||
661 *mdefs->variant[rule->variant_num] == '\0')
663 if (strcmp(rule->variant, "*") == 0) {
666 if (rule->variant[0] == '$') {
667 if (!CheckGroup(rules, rule->variant,
668 mdefs->variant[rule->variant_num]))
671 if (strcmp(rule->variant,
672 mdefs->variant[rule->variant_num]) != 0)
678 rule->flags|= XkbRF_PendingMatch;
681 /* exact match, apply it now */
682 XkbRF_ApplyRule(rule,names);
687 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
692 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
693 rule->flags&= ~XkbRF_PendingMatch;
698 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,struct xkb_component_names * names)
703 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
704 if ((rule->flags&XkbRF_PendingMatch)==0)
706 XkbRF_ApplyRule(rule,names);
711 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
712 XkbRF_MultiDefsPtr mdefs,
713 struct xkb_component_names * names,
720 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
721 if ((rule->flags & flags) != flags)
723 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
724 if (skip && !(flags & XkbRF_Option)) {
725 for ( ;(i < rules->num_rules) && (rule->number == skip);
732 /***====================================================================***/
735 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
737 char *str, *outstr, *orig, *var;
742 str= strchr(name,'%');
749 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
758 str = get_index(var + 1, &ndx);
760 str = strchr(str,'%');
763 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
764 len+= strlen(mdefs->layout[ndx])+extra_len;
765 else if ((*var=='m')&&mdefs->model)
766 len+= strlen(mdefs->model)+extra_len;
767 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
768 len+= strlen(mdefs->variant[ndx])+extra_len;
769 if ((pfx=='(')&&(*str==')')) {
772 str= strchr(&str[0],'%');
774 name = malloc(len + 1);
783 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
793 str = get_index(var + 1, &ndx);
797 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
798 if (pfx) *outstr++= pfx;
799 strcpy(outstr,mdefs->layout[ndx]);
800 outstr+= strlen(mdefs->layout[ndx]);
801 if (sfx) *outstr++= sfx;
803 else if ((*var=='m')&&(mdefs->model)) {
804 if (pfx) *outstr++= pfx;
805 strcpy(outstr,mdefs->model);
806 outstr+= strlen(mdefs->model);
807 if (sfx) *outstr++= sfx;
809 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
810 if (pfx) *outstr++= pfx;
811 strcpy(outstr,mdefs->variant[ndx]);
812 outstr+= strlen(mdefs->variant[ndx]);
813 if (sfx) *outstr++= sfx;
815 if ((pfx=='(')&&(*str==')'))
828 /***====================================================================***/
831 XkbcRF_GetComponents( XkbRF_RulesPtr rules,
832 XkbRF_VarDefsPtr defs,
833 struct xkb_component_names * names)
835 XkbRF_MultiDefsRec mdefs;
837 MakeMultiDefs(&mdefs, defs);
839 memset(names, 0, sizeof(struct xkb_component_names));
840 XkbRF_ClearPartialMatches(rules);
841 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
842 XkbRF_ApplyPartialMatches(rules, names);
843 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
844 XkbRF_ApplyPartialMatches(rules, names);
845 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
846 XkbRF_ApplyPartialMatches(rules, names);
849 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
851 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
853 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
855 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
857 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
859 FreeMultiDefs(&mdefs);
860 return (names->keycodes && names->symbols && names->types &&
861 names->compat) || names->keymap;
865 XkbcRF_AddRule(XkbRF_RulesPtr rules)
867 if (rules->sz_rules<1) {
870 rules->rules= uTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
872 else if (rules->num_rules>=rules->sz_rules) {
874 rules->rules= uTypedRealloc(rules->rules,rules->sz_rules,
878 rules->sz_rules= rules->num_rules= 0;
880 fprintf(stderr,"Allocation failure in XkbcRF_AddRule\n");
884 memset(&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
885 return &rules->rules[rules->num_rules++];
888 static XkbRF_GroupPtr
889 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
891 if (rules->sz_groups<1) {
892 rules->sz_groups= 16;
893 rules->num_groups= 0;
894 rules->groups= uTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
896 else if (rules->num_groups >= rules->sz_groups) {
897 rules->sz_groups *= 2;
898 rules->groups= uTypedRealloc(rules->groups,rules->sz_groups,
901 if (!rules->groups) {
902 rules->sz_groups= rules->num_groups= 0;
906 memset(&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec));
907 return &rules->groups[rules->num_groups++];
911 XkbcRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
915 XkbRF_RuleRec trule,*rule;
916 XkbRF_GroupRec tgroup,*group;
918 if (!(rules && file))
920 memset(&remap, 0, sizeof(RemapSpec));
921 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
922 InitInputLine(&line);
923 while (GetInputLine(file, &line, true)) {
924 if (CheckLine(&line,&remap,&trule,&tgroup)) {
926 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
928 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
931 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
933 memset(&trule, 0, sizeof(XkbRF_RuleRec));
939 FreeInputLine(&line);
944 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
948 for (i=0;i<var->num_desc;i++) {
949 free(var->desc[i].name);
950 free(var->desc[i].desc);
951 var->desc[i].name= var->desc[i].desc= NULL;
958 XkbcRF_Free(XkbRF_RulesPtr rules)
962 XkbRF_GroupPtr group;
966 XkbRF_ClearVarDescriptions(&rules->models);
967 XkbRF_ClearVarDescriptions(&rules->layouts);
968 XkbRF_ClearVarDescriptions(&rules->variants);
969 XkbRF_ClearVarDescriptions(&rules->options);
971 for (i = 0; i < rules->num_extra; i++) {
972 XkbRF_ClearVarDescriptions(&rules->extra[i]);
976 for (i=0, rule = rules->rules; i < rules->num_rules && rules; i++, rule++) {
981 free(rule->keycodes);
989 for (i=0, group = rules->groups; i < rules->num_groups && group; i++, group++) {