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 ********************************************************/
32 #include "xkbcommon/xkbcommon.h"
33 #include "XKBcommonint.h"
39 #define X_INCLUDE_STRING_H
40 #define XOS_USE_NO_LOCKING
41 #include <X11/Xos_r.h>
43 #include <X11/Xproto.h>
46 #include <X11/Xfuncs.h>
49 #define PR_DEBUG(s) fprintf(stderr,s)
50 #define PR_DEBUG1(s,a) fprintf(stderr,s,a)
51 #define PR_DEBUG2(s,a,b) fprintf(stderr,s,a,b)
54 #define PR_DEBUG1(s,a)
55 #define PR_DEBUG2(s,a,b)
58 /***====================================================================***/
60 #define DFLT_LINE_SIZE 128
66 char buf[DFLT_LINE_SIZE];
71 InitInputLine(InputLine *line)
75 line->sz_line= DFLT_LINE_SIZE;
76 line->line= line->buf;
80 FreeInputLine(InputLine *line)
82 if (line->line!=line->buf)
86 line->sz_line= DFLT_LINE_SIZE;
87 line->line= line->buf;
91 InputLineAddChar(InputLine *line,int ch)
93 if (line->num_line>=line->sz_line) {
94 if (line->line==line->buf) {
95 line->line = malloc(line->sz_line * 2);
96 memcpy(line->line,line->buf,line->sz_line);
99 line->line = realloc(line->line, line->sz_line * 2);
103 line->line[line->num_line++]= ch;
107 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
108 (int)((l)->line[(l)->num_line++]= (c)):\
109 InputLineAddChar(l,c))
112 GetInputLine(FILE *file,InputLine *line,Bool checkbang)
115 Bool endOfFile,spacePending,slashPending,inComment;
118 while ((!endOfFile)&&(line->num_line==0)) {
119 spacePending= slashPending= inComment= False;
120 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
122 if ((ch=getc(file))==EOF)
142 else if (slashPending) {
151 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
156 if ((ch!='\n')&&(line->num_line>0))
165 if (checkbang && ch=='!') {
166 if (line->num_line!=0) {
167 PR_DEBUG("The '!' legal only at start of line\n");
168 PR_DEBUG("Line containing '!' ignored\n");
179 /* else line->num_line++;*/
181 if ((line->num_line==0)&&(endOfFile))
187 /***====================================================================***/
201 #define PART_MASK 0x000F
202 #define COMPONENT_MASK 0x03F0
204 static const char * cname[MAX_WORDS] = {
205 "model", "layout", "variant", "option",
206 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
209 typedef struct _RemapSpec {
218 typedef struct _FileSpec {
219 char * name[MAX_WORDS];
220 struct _FileSpec * pending;
225 const char * layout[XkbNumKbdGroups+1];
226 const char * variant[XkbNumKbdGroups+1];
228 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
230 #define NDX_BUFF_SIZE 4
232 /***====================================================================***/
235 get_index(char *str, int *ndx)
237 char ndx_buf[NDX_BUFF_SIZE];
245 end = strchr(str, ']');
250 if ( (end - str) >= NDX_BUFF_SIZE) {
254 strncpy(ndx_buf, str, end - str);
255 ndx_buf[end - str] = '\0';
256 *ndx = atoi(ndx_buf);
261 SetUpRemap(InputLine *line,RemapSpec *remap)
264 unsigned present, l_ndx_present, v_ndx_present;
268 _Xstrtokparams strtok_buf;
274 l_ndx_present = v_ndx_present = present= 0;
277 memset(remap, 0, sizeof(RemapSpec));
279 while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
284 if (strcmp(tok,"=")==0)
286 for (i=0;i<MAX_WORDS;i++) {
287 len = strlen(cname[i]);
288 if (strncmp(cname[i],tok,len)==0) {
289 if(strlen(tok) > len) {
290 char *end = get_index(tok+len, &ndx);
291 if ((i != LAYOUT && i != VARIANT) ||
292 *end != '\0' || ndx == -1)
294 if (ndx < 1 || ndx > XkbNumKbdGroups) {
295 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
296 PR_DEBUG1("Index must be in range 1..%d\n",
306 if (present&(1<<i)) {
307 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
308 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
309 PR_DEBUG1("Component \"%s\" listed twice\n",tok);
310 PR_DEBUG("Second definition ignored\n");
316 l_ndx_present |= 1 << ndx;
318 v_ndx_present |= 1 << ndx;
319 remap->remap[remap->num_remap].word= i;
320 remap->remap[remap->num_remap++].index= ndx;
326 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
330 if ((present&PART_MASK)==0) {
332 unsigned mask= PART_MASK;
333 fprintf(stderr,"Mapping needs at least one of ");
334 for (i=0; (i<MAX_WORDS); i++) {
337 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
338 else fprintf(stderr,"or \"%s\"\n",cname[i]);
341 fprintf(stderr,"Illegal mapping ignored\n");
346 if ((present&COMPONENT_MASK)==0) {
347 PR_DEBUG("Mapping needs at least one component\n");
348 PR_DEBUG("Illegal mapping ignored\n");
352 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
353 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
354 PR_DEBUG("Keymap cannot appear with other components\n");
355 PR_DEBUG("Illegal mapping ignored\n");
363 MatchOneOf(char *wanted,char *vals_defined)
366 int want_len = strlen(wanted);
368 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
370 next= strchr(str,',');
378 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
384 /***====================================================================***/
387 CheckLine( InputLine * line,
390 XkbRF_GroupPtr group)
395 _Xstrtokparams strtok_buf;
398 if (line->line[0]=='!') {
399 if (line->line[1] == '$' ||
400 (line->line[1] == ' ' && line->line[2] == '$')) {
401 char *gname = strchr(line->line, '$');
402 char *words = strchr(gname, ' ');
406 for (; *words; words++) {
407 if (*words != '=' && *words != ' ')
412 group->name = uDupString(gname);
413 group->words = uDupString(words);
414 for (i = 1, words = group->words; *words; words++) {
415 if ( *words == ' ') {
423 SetUpRemap(line,remap);
428 if (remap->num_remap==0) {
429 PR_DEBUG("Must have a mapping before first line of data\n");
430 PR_DEBUG("Illegal line of data ignored\n");
433 memset(&tmp, 0, sizeof(FileSpec));
435 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
437 if (strcmp(tok,"=")==0) {
441 if (nread>remap->num_remap) {
442 PR_DEBUG("Too many words on a line\n");
443 PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
446 tmp.name[remap->remap[nread].word]= tok;
447 if (*tok == '+' || *tok == '|')
450 if (nread<remap->num_remap) {
451 PR_DEBUG1("Too few words on a line: %s\n", line->line);
452 PR_DEBUG("line ignored\n");
457 rule->number = remap->number;
458 if (tmp.name[OPTION])
459 rule->flags|= XkbRF_Option;
461 rule->flags|= XkbRF_Append;
463 rule->flags|= XkbRF_Normal;
464 rule->model= uDupString(tmp.name[MODEL]);
465 rule->layout= uDupString(tmp.name[LAYOUT]);
466 rule->variant= uDupString(tmp.name[VARIANT]);
467 rule->option= uDupString(tmp.name[OPTION]);
469 rule->keycodes= uDupString(tmp.name[KEYCODES]);
470 rule->symbols= uDupString(tmp.name[SYMBOLS]);
471 rule->types= uDupString(tmp.name[TYPES]);
472 rule->compat= uDupString(tmp.name[COMPAT]);
473 rule->keymap= uDupString(tmp.name[KEYMAP]);
475 rule->layout_num = rule->variant_num = 0;
476 for (i = 0; i < nread; i++) {
477 if (remap->remap[i].index) {
478 if (remap->remap[i].word == LAYOUT)
479 rule->layout_num = remap->remap[i].index;
480 if (remap->remap[i].word == VARIANT)
481 rule->variant_num = remap->remap[i].index;
488 _Concat(char *str1,char *str2)
492 if ((!str1)||(!str2))
494 len= strlen(str1)+strlen(str2)+1;
495 str1 = uTypedRealloc(str1, len, char);
502 squeeze_spaces(char *p1)
505 for (p2 = p1; *p2; p2++) {
507 if (*p1 != ' ') p1++;
513 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
515 memset(mdefs, 0, sizeof(XkbRF_MultiDefsRec));
516 mdefs->model = defs->model;
517 mdefs->options = uDupString(defs->options);
518 if (mdefs->options) squeeze_spaces(mdefs->options);
521 if (!strchr(defs->layout, ',')) {
522 mdefs->layout[0] = defs->layout;
526 p = uDupString(defs->layout);
530 mdefs->layout[1] = p;
531 for (i = 2; i <= XkbNumKbdGroups; i++) {
532 if ((p = strchr(p, ','))) {
534 mdefs->layout[i] = p;
539 if (p && (p = strchr(p, ',')))
545 if (!strchr(defs->variant, ',')) {
546 mdefs->variant[0] = defs->variant;
550 p = uDupString(defs->variant);
554 mdefs->variant[1] = p;
555 for (i = 2; i <= XkbNumKbdGroups; i++) {
556 if ((p = strchr(p, ','))) {
558 mdefs->variant[i] = p;
563 if (p && (p = strchr(p, ',')))
571 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
574 /* Avoid -Wcast-qual warnings. */
575 free((void *)(uintptr_t)defs->layout[1]);
576 free((void *)(uintptr_t)defs->variant[1]);
580 Apply(char *src, char **dst)
583 if (*src == '+' || *src == '!') {
584 *dst= _Concat(*dst, src);
587 *dst= uDupString(src);
593 XkbRF_ApplyRule( XkbRF_RulePtr rule,
594 struct xkb_component_names * names)
596 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
598 Apply(rule->keycodes, &names->keycodes);
599 Apply(rule->symbols, &names->symbols);
600 Apply(rule->types, &names->types);
601 Apply(rule->compat, &names->compat);
602 Apply(rule->keymap, &names->keymap);
606 CheckGroup( XkbRF_RulesPtr rules,
607 const char * group_name,
612 XkbRF_GroupPtr group;
614 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
615 if (! strcmp(group->name, group_name)) {
619 if (i == rules->num_groups)
621 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
622 if (! strcmp(p, name)) {
630 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
631 XkbRF_MultiDefsPtr mdefs,
632 struct xkb_component_names * names,
633 XkbRF_RulesPtr rules)
635 Bool pending = False;
637 if (rule->model != NULL) {
638 if(mdefs->model == NULL)
640 if (strcmp(rule->model, "*") == 0) {
643 if (rule->model[0] == '$') {
644 if (!CheckGroup(rules, rule->model, mdefs->model))
647 if (strcmp(rule->model, mdefs->model) != 0)
652 if (rule->option != NULL) {
653 if (mdefs->options == NULL)
655 if ((!MatchOneOf(rule->option,mdefs->options)))
659 if (rule->layout != NULL) {
660 if(mdefs->layout[rule->layout_num] == NULL ||
661 *mdefs->layout[rule->layout_num] == '\0')
663 if (strcmp(rule->layout, "*") == 0) {
666 if (rule->layout[0] == '$') {
667 if (!CheckGroup(rules, rule->layout,
668 mdefs->layout[rule->layout_num]))
671 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
676 if (rule->variant != NULL) {
677 if (mdefs->variant[rule->variant_num] == NULL ||
678 *mdefs->variant[rule->variant_num] == '\0')
680 if (strcmp(rule->variant, "*") == 0) {
683 if (rule->variant[0] == '$') {
684 if (!CheckGroup(rules, rule->variant,
685 mdefs->variant[rule->variant_num]))
688 if (strcmp(rule->variant,
689 mdefs->variant[rule->variant_num]) != 0)
695 rule->flags|= XkbRF_PendingMatch;
698 /* exact match, apply it now */
699 XkbRF_ApplyRule(rule,names);
704 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
709 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
710 rule->flags&= ~XkbRF_PendingMatch;
715 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,struct xkb_component_names * names)
720 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
721 if ((rule->flags&XkbRF_PendingMatch)==0)
723 XkbRF_ApplyRule(rule,names);
728 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
729 XkbRF_MultiDefsPtr mdefs,
730 struct xkb_component_names * names,
737 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
738 if ((rule->flags & flags) != flags)
740 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
741 if (skip && !(flags & XkbRF_Option)) {
742 for ( ;(i < rules->num_rules) && (rule->number == skip);
749 /***====================================================================***/
752 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
754 char *str, *outstr, *orig, *var;
759 str= strchr(name,'%');
766 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
775 str = get_index(var + 1, &ndx);
777 str = strchr(str,'%');
780 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
781 len+= strlen(mdefs->layout[ndx])+extra_len;
782 else if ((*var=='m')&&mdefs->model)
783 len+= strlen(mdefs->model)+extra_len;
784 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
785 len+= strlen(mdefs->variant[ndx])+extra_len;
786 if ((pfx=='(')&&(*str==')')) {
789 str= strchr(&str[0],'%');
791 name = malloc(len + 1);
800 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
810 str = get_index(var + 1, &ndx);
814 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
815 if (pfx) *outstr++= pfx;
816 strcpy(outstr,mdefs->layout[ndx]);
817 outstr+= strlen(mdefs->layout[ndx]);
818 if (sfx) *outstr++= sfx;
820 else if ((*var=='m')&&(mdefs->model)) {
821 if (pfx) *outstr++= pfx;
822 strcpy(outstr,mdefs->model);
823 outstr+= strlen(mdefs->model);
824 if (sfx) *outstr++= sfx;
826 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
827 if (pfx) *outstr++= pfx;
828 strcpy(outstr,mdefs->variant[ndx]);
829 outstr+= strlen(mdefs->variant[ndx]);
830 if (sfx) *outstr++= sfx;
832 if ((pfx=='(')&&(*str==')'))
845 /***====================================================================***/
848 XkbcRF_GetComponents( XkbRF_RulesPtr rules,
849 XkbRF_VarDefsPtr defs,
850 struct xkb_component_names * names)
852 XkbRF_MultiDefsRec mdefs;
854 MakeMultiDefs(&mdefs, defs);
856 memset(names, 0, sizeof(struct xkb_component_names));
857 XkbRF_ClearPartialMatches(rules);
858 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
859 XkbRF_ApplyPartialMatches(rules, names);
860 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
861 XkbRF_ApplyPartialMatches(rules, names);
862 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
863 XkbRF_ApplyPartialMatches(rules, names);
866 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
868 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
870 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
872 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
874 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
876 FreeMultiDefs(&mdefs);
877 return (names->keycodes && names->symbols && names->types &&
878 names->compat) || names->keymap;
882 XkbcRF_AddRule(XkbRF_RulesPtr rules)
884 if (rules->sz_rules<1) {
887 rules->rules= uTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
889 else if (rules->num_rules>=rules->sz_rules) {
891 rules->rules= uTypedRealloc(rules->rules,rules->sz_rules,
895 rules->sz_rules= rules->num_rules= 0;
897 fprintf(stderr,"Allocation failure in XkbcRF_AddRule\n");
901 memset(&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
902 return &rules->rules[rules->num_rules++];
905 static XkbRF_GroupPtr
906 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
908 if (rules->sz_groups<1) {
909 rules->sz_groups= 16;
910 rules->num_groups= 0;
911 rules->groups= uTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
913 else if (rules->num_groups >= rules->sz_groups) {
914 rules->sz_groups *= 2;
915 rules->groups= uTypedRealloc(rules->groups,rules->sz_groups,
918 if (!rules->groups) {
919 rules->sz_groups= rules->num_groups= 0;
923 memset(&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec));
924 return &rules->groups[rules->num_groups++];
928 XkbcRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
932 XkbRF_RuleRec trule,*rule;
933 XkbRF_GroupRec tgroup,*group;
935 if (!(rules && file))
937 memset(&remap, 0, sizeof(RemapSpec));
938 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
939 InitInputLine(&line);
940 while (GetInputLine(file,&line,True)) {
941 if (CheckLine(&line,&remap,&trule,&tgroup)) {
943 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
945 memset(&tgroup, 0, sizeof(XkbRF_GroupRec));
948 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
950 memset(&trule, 0, sizeof(XkbRF_RuleRec));
956 FreeInputLine(&line);
961 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
965 for (i=0;i<var->num_desc;i++) {
966 free(var->desc[i].name);
967 free(var->desc[i].desc);
968 var->desc[i].name= var->desc[i].desc= NULL;
975 XkbcRF_Free(XkbRF_RulesPtr rules)
979 XkbRF_GroupPtr group;
983 XkbRF_ClearVarDescriptions(&rules->models);
984 XkbRF_ClearVarDescriptions(&rules->layouts);
985 XkbRF_ClearVarDescriptions(&rules->variants);
986 XkbRF_ClearVarDescriptions(&rules->options);
988 for (i = 0; i < rules->num_extra; i++) {
989 XkbRF_ClearVarDescriptions(&rules->extra[i]);
993 for (i=0, rule = rules->rules; i < rules->num_rules && rules; i++, rule++) {
998 free(rule->keycodes);
1006 for (i=0, group = rules->groups; i < rules->num_groups && group; i++, group++) {
1010 free(rules->groups);