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 ********************************************************/
31 #include "X11/extensions/XKBcommon.h"
32 #include "XKBcommonint.h"
34 #ifdef HAVE_DIX_CONFIG_H
35 #include <dix-config.h>
36 #elif defined(HAVE_CONFIG_H)
44 #define X_INCLUDE_STRING_H
45 #define XOS_USE_NO_LOCKING
46 #include <X11/Xos_r.h>
48 #include <X11/Xproto.h>
51 #include <X11/Xfuncs.h>
54 #define PR_DEBUG(s) fprintf(stderr,s)
55 #define PR_DEBUG1(s,a) fprintf(stderr,s,a)
56 #define PR_DEBUG2(s,a,b) fprintf(stderr,s,a,b)
59 #define PR_DEBUG1(s,a)
60 #define PR_DEBUG2(s,a,b)
63 /***====================================================================***/
65 #define DFLT_LINE_SIZE 128
71 char buf[DFLT_LINE_SIZE];
76 InitInputLine(InputLine *line)
80 line->sz_line= DFLT_LINE_SIZE;
81 line->line= line->buf;
86 FreeInputLine(InputLine *line)
88 if (line->line!=line->buf)
92 line->sz_line= DFLT_LINE_SIZE;
93 line->line= line->buf;
98 InputLineAddChar(InputLine *line,int ch)
100 if (line->num_line>=line->sz_line) {
101 if (line->line==line->buf) {
102 line->line= (char *)_XkbAlloc(line->sz_line*2);
103 memcpy(line->line,line->buf,line->sz_line);
106 line->line=(char *)_XkbRealloc((char *)line->line,line->sz_line*2);
110 line->line[line->num_line++]= ch;
114 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
115 (int)((l)->line[(l)->num_line++]= (c)):\
116 InputLineAddChar(l,c))
119 GetInputLine(FILE *file,InputLine *line,Bool checkbang)
122 Bool endOfFile,spacePending,slashPending,inComment;
125 while ((!endOfFile)&&(line->num_line==0)) {
126 spacePending= slashPending= inComment= False;
127 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
129 if ((ch=getc(file))==EOF)
149 else if (slashPending) {
158 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
163 if ((ch!='\n')&&(line->num_line>0))
172 if (checkbang && ch=='!') {
173 if (line->num_line!=0) {
174 PR_DEBUG("The '!' legal only at start of line\n");
175 PR_DEBUG("Line containing '!' ignored\n");
187 /* else line->num_line++;*/
189 if ((line->num_line==0)&&(endOfFile))
195 /***====================================================================***/
209 #define PART_MASK 0x000F
210 #define COMPONENT_MASK 0x03F0
212 static char * cname[MAX_WORDS] = {
213 "model", "layout", "variant", "option",
214 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
217 typedef struct _RemapSpec {
226 typedef struct _FileSpec {
227 char * name[MAX_WORDS];
228 struct _FileSpec * pending;
233 char * layout[XkbNumKbdGroups+1];
234 char * variant[XkbNumKbdGroups+1];
236 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
238 #define NDX_BUFF_SIZE 4
240 /***====================================================================***/
243 get_index(char *str, int *ndx)
245 char ndx_buf[NDX_BUFF_SIZE];
253 end = strchr(str, ']');
258 if ( (end - str) >= NDX_BUFF_SIZE) {
262 strncpy(ndx_buf, str, end - str);
263 ndx_buf[end - str] = '\0';
264 *ndx = atoi(ndx_buf);
269 SetUpRemap(InputLine *line,RemapSpec *remap)
272 unsigned present, l_ndx_present, v_ndx_present;
275 _Xstrtokparams strtok_buf;
281 l_ndx_present = v_ndx_present = present= 0;
284 bzero((char *)remap,sizeof(RemapSpec));
286 while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
291 if (strcmp(tok,"=")==0)
293 for (i=0;i<MAX_WORDS;i++) {
294 len = strlen(cname[i]);
295 if (strncmp(cname[i],tok,len)==0) {
296 if(strlen(tok) > len) {
297 char *end = get_index(tok+len, &ndx);
298 if ((i != LAYOUT && i != VARIANT) ||
299 *end != '\0' || ndx == -1)
301 if (ndx < 1 || ndx > XkbNumKbdGroups) {
302 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
303 PR_DEBUG1("Index must be in range 1..%d\n",
313 if (present&(1<<i)) {
314 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
315 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
316 PR_DEBUG1("Component \"%s\" listed twice\n",tok);
317 PR_DEBUG("Second definition ignored\n");
323 l_ndx_present |= 1 << ndx;
325 v_ndx_present |= 1 << ndx;
326 remap->remap[remap->num_remap].word= i;
327 remap->remap[remap->num_remap++].index= ndx;
333 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
337 if ((present&PART_MASK)==0) {
339 unsigned mask= PART_MASK;
340 fprintf(stderr,"Mapping needs at least one of ");
341 for (i=0; (i<MAX_WORDS); i++) {
344 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
345 else fprintf(stderr,"or \"%s\"\n",cname[i]);
348 fprintf(stderr,"Illegal mapping ignored\n");
353 if ((present&COMPONENT_MASK)==0) {
354 PR_DEBUG("Mapping needs at least one component\n");
355 PR_DEBUG("Illegal mapping ignored\n");
359 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
360 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
361 PR_DEBUG("Keymap cannot appear with other components\n");
362 PR_DEBUG("Illegal mapping ignored\n");
371 MatchOneOf(char *wanted,char *vals_defined)
374 int want_len= strlen(wanted);
376 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
378 next= strchr(str,',');
386 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
392 /***====================================================================***/
395 CheckLine( InputLine * line,
398 XkbRF_GroupPtr group)
401 register int nread, i;
403 _Xstrtokparams strtok_buf;
406 if (line->line[0]=='!') {
407 if (line->line[1] == '$' ||
408 (line->line[1] == ' ' && line->line[2] == '$')) {
409 char *gname = strchr(line->line, '$');
410 char *words = strchr(gname, ' ');
414 for (; *words; words++) {
415 if (*words != '=' && *words != ' ')
420 group->name = _XkbDupString(gname);
421 group->words = _XkbDupString(words);
422 for (i = 1, words = group->words; *words; words++) {
423 if ( *words == ' ') {
431 SetUpRemap(line,remap);
436 if (remap->num_remap==0) {
437 PR_DEBUG("Must have a mapping before first line of data\n");
438 PR_DEBUG("Illegal line of data ignored\n");
441 bzero((char *)&tmp,sizeof(FileSpec));
443 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
445 if (strcmp(tok,"=")==0) {
449 if (nread>remap->num_remap) {
450 PR_DEBUG("Too many words on a line\n");
451 PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
454 tmp.name[remap->remap[nread].word]= tok;
455 if (*tok == '+' || *tok == '|')
458 if (nread<remap->num_remap) {
459 PR_DEBUG1("Too few words on a line: %s\n", line->line);
460 PR_DEBUG("line ignored\n");
465 rule->number = remap->number;
466 if (tmp.name[OPTION])
467 rule->flags|= XkbRF_Option;
469 rule->flags|= XkbRF_Append;
471 rule->flags|= XkbRF_Normal;
472 rule->model= _XkbDupString(tmp.name[MODEL]);
473 rule->layout= _XkbDupString(tmp.name[LAYOUT]);
474 rule->variant= _XkbDupString(tmp.name[VARIANT]);
475 rule->option= _XkbDupString(tmp.name[OPTION]);
477 rule->keycodes= _XkbDupString(tmp.name[KEYCODES]);
478 rule->symbols= _XkbDupString(tmp.name[SYMBOLS]);
479 rule->types= _XkbDupString(tmp.name[TYPES]);
480 rule->compat= _XkbDupString(tmp.name[COMPAT]);
481 rule->geometry= _XkbDupString(tmp.name[GEOMETRY]);
482 rule->keymap= _XkbDupString(tmp.name[KEYMAP]);
484 rule->layout_num = rule->variant_num = 0;
485 for (i = 0; i < nread; i++) {
486 if (remap->remap[i].index) {
487 if (remap->remap[i].word == LAYOUT)
488 rule->layout_num = remap->remap[i].index;
489 if (remap->remap[i].word == VARIANT)
490 rule->variant_num = remap->remap[i].index;
497 _Concat(char *str1,char *str2)
501 if ((!str1)||(!str2))
503 len= strlen(str1)+strlen(str2)+1;
504 str1= _XkbTypedRealloc(str1,len,char);
511 squeeze_spaces(char *p1)
514 for (p2 = p1; *p2; p2++) {
516 if (*p1 != ' ') p1++;
522 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
525 bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec));
526 mdefs->model = defs->model;
527 mdefs->options = _XkbDupString(defs->options);
528 if (mdefs->options) squeeze_spaces(mdefs->options);
531 if (!strchr(defs->layout, ',')) {
532 mdefs->layout[0] = defs->layout;
536 mdefs->layout[1] = _XkbDupString(defs->layout);
537 if (mdefs->layout[1] == NULL)
539 squeeze_spaces(mdefs->layout[1]);
540 p = mdefs->layout[1];
541 for (i = 2; i <= XkbNumKbdGroups; i++) {
542 if ((p = strchr(p, ','))) {
544 mdefs->layout[i] = p;
549 if (p && (p = strchr(p, ',')))
555 if (!strchr(defs->variant, ',')) {
556 mdefs->variant[0] = defs->variant;
560 mdefs->variant[1] = _XkbDupString(defs->variant);
561 if (mdefs->variant[1] == NULL)
563 squeeze_spaces(mdefs->variant[1]);
564 p = mdefs->variant[1];
565 for (i = 2; i <= XkbNumKbdGroups; i++) {
566 if ((p = strchr(p, ','))) {
568 mdefs->variant[i] = p;
573 if (p && (p = strchr(p, ',')))
581 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
583 if (defs->options) _XkbFree(defs->options);
584 if (defs->layout[1]) _XkbFree(defs->layout[1]);
585 if (defs->variant[1]) _XkbFree(defs->variant[1]);
589 Apply(char *src, char **dst)
592 if (*src == '+' || *src == '!') {
593 *dst= _Concat(*dst, src);
596 *dst= _XkbDupString(src);
602 XkbRF_ApplyRule( XkbRF_RulePtr rule,
603 XkbComponentNamesPtr names)
605 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
607 Apply(rule->keycodes, &names->keycodes);
608 Apply(rule->symbols, &names->symbols);
609 Apply(rule->types, &names->types);
610 Apply(rule->compat, &names->compat);
611 Apply(rule->geometry, &names->geometry);
612 Apply(rule->keymap, &names->keymap);
616 CheckGroup( XkbRF_RulesPtr rules,
622 XkbRF_GroupPtr group;
624 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
625 if (! strcmp(group->name, group_name)) {
629 if (i == rules->num_groups)
631 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
632 if (! strcmp(p, name)) {
640 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
641 XkbRF_MultiDefsPtr mdefs,
642 XkbComponentNamesPtr names,
643 XkbRF_RulesPtr rules)
645 Bool pending = False;
647 if (rule->model != NULL) {
648 if(mdefs->model == NULL)
650 if (strcmp(rule->model, "*") == 0) {
653 if (rule->model[0] == '$') {
654 if (!CheckGroup(rules, rule->model, mdefs->model))
657 if (strcmp(rule->model, mdefs->model) != 0)
662 if (rule->option != NULL) {
663 if (mdefs->options == NULL)
665 if ((!MatchOneOf(rule->option,mdefs->options)))
669 if (rule->layout != NULL) {
670 if(mdefs->layout[rule->layout_num] == NULL ||
671 *mdefs->layout[rule->layout_num] == '\0')
673 if (strcmp(rule->layout, "*") == 0) {
676 if (rule->layout[0] == '$') {
677 if (!CheckGroup(rules, rule->layout,
678 mdefs->layout[rule->layout_num]))
681 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
686 if (rule->variant != NULL) {
687 if (mdefs->variant[rule->variant_num] == NULL ||
688 *mdefs->variant[rule->variant_num] == '\0')
690 if (strcmp(rule->variant, "*") == 0) {
693 if (rule->variant[0] == '$') {
694 if (!CheckGroup(rules, rule->variant,
695 mdefs->variant[rule->variant_num]))
698 if (strcmp(rule->variant,
699 mdefs->variant[rule->variant_num]) != 0)
705 rule->flags|= XkbRF_PendingMatch;
708 /* exact match, apply it now */
709 XkbRF_ApplyRule(rule,names);
714 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
719 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
720 rule->flags&= ~XkbRF_PendingMatch;
725 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names)
730 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
731 if ((rule->flags&XkbRF_PendingMatch)==0)
733 XkbRF_ApplyRule(rule,names);
738 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
739 XkbRF_MultiDefsPtr mdefs,
740 XkbComponentNamesPtr names,
747 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
748 if ((rule->flags & flags) != flags)
750 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
751 if (skip && !(flags & XkbRF_Option)) {
752 for ( ;(i < rules->num_rules) && (rule->number == skip);
759 /***====================================================================***/
762 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
764 char *str, *outstr, *orig, *var;
768 str= index(name,'%');
775 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
784 str = get_index(var + 1, &ndx);
786 str = index(str,'%');
789 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
790 len+= strlen(mdefs->layout[ndx])+extra_len;
791 else if ((*var=='m')&&mdefs->model)
792 len+= strlen(mdefs->model)+extra_len;
793 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
794 len+= strlen(mdefs->variant[ndx])+extra_len;
795 if ((pfx=='(')&&(*str==')')) {
798 str= index(&str[0],'%');
800 name= (char *)_XkbAlloc(len+1);
809 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
819 str = get_index(var + 1, &ndx);
823 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
824 if (pfx) *outstr++= pfx;
825 strcpy(outstr,mdefs->layout[ndx]);
826 outstr+= strlen(mdefs->layout[ndx]);
827 if (sfx) *outstr++= sfx;
829 else if ((*var=='m')&&(mdefs->model)) {
830 if (pfx) *outstr++= pfx;
831 strcpy(outstr,mdefs->model);
832 outstr+= strlen(mdefs->model);
833 if (sfx) *outstr++= sfx;
835 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
836 if (pfx) *outstr++= pfx;
837 strcpy(outstr,mdefs->variant[ndx]);
838 outstr+= strlen(mdefs->variant[ndx]);
839 if (sfx) *outstr++= sfx;
841 if ((pfx=='(')&&(*str==')'))
854 /***====================================================================***/
857 XkbcRF_GetComponents( XkbRF_RulesPtr rules,
858 XkbRF_VarDefsPtr defs,
859 XkbComponentNamesPtr names)
861 XkbRF_MultiDefsRec mdefs;
863 MakeMultiDefs(&mdefs, defs);
865 bzero((char *)names,sizeof(XkbComponentNamesRec));
866 XkbRF_ClearPartialMatches(rules);
867 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
868 XkbRF_ApplyPartialMatches(rules, names);
869 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
870 XkbRF_ApplyPartialMatches(rules, names);
871 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
872 XkbRF_ApplyPartialMatches(rules, names);
875 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
877 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
879 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
881 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
883 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
885 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
887 FreeMultiDefs(&mdefs);
888 return (names->keycodes && names->symbols && names->types &&
889 names->compat && names->geometry ) || names->keymap;
893 XkbcRF_AddRule(XkbRF_RulesPtr rules)
895 if (rules->sz_rules<1) {
898 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
900 else if (rules->num_rules>=rules->sz_rules) {
902 rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
906 rules->sz_rules= rules->num_rules= 0;
908 fprintf(stderr,"Allocation failure in XkbcRF_AddRule\n");
912 bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec));
913 return &rules->rules[rules->num_rules++];
917 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
919 if (rules->sz_groups<1) {
920 rules->sz_groups= 16;
921 rules->num_groups= 0;
922 rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
924 else if (rules->num_groups >= rules->sz_groups) {
925 rules->sz_groups *= 2;
926 rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups,
929 if (!rules->groups) {
930 rules->sz_groups= rules->num_groups= 0;
934 bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec));
935 return &rules->groups[rules->num_groups++];
939 XkbcRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
943 XkbRF_RuleRec trule,*rule;
944 XkbRF_GroupRec tgroup,*group;
946 if (!(rules && file))
948 bzero((char *)&remap,sizeof(RemapSpec));
949 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
950 InitInputLine(&line);
951 while (GetInputLine(file,&line,True)) {
952 if (CheckLine(&line,&remap,&trule,&tgroup)) {
954 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
956 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
959 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
961 bzero((char *)&trule,sizeof(XkbRF_RuleRec));
967 FreeInputLine(&line);
972 XkbcRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules)
978 if ((!base)||(!rules))
981 if (strlen(base)+strlen(locale)+2 > PATH_MAX)
983 sprintf(buf,"%s-%s", base, locale);
986 if (strlen(base)+1 > PATH_MAX)
991 file= fopen(buf, "r");
992 if ((!file)&&(locale)) { /* fallback if locale was specified */
994 file= fopen(buf, "r");
998 ok= XkbcRF_LoadRules(file,rules);
1003 /***====================================================================***/
1006 #define HEAD_MODEL 1
1007 #define HEAD_LAYOUT 2
1008 #define HEAD_VARIANT 3
1009 #define HEAD_OPTION 4
1010 #define HEAD_EXTRA 5
1013 XkbcRF_AddVarDesc(XkbRF_DescribeVarsPtr vars)
1015 if (vars->sz_desc<1) {
1018 vars->desc= _XkbTypedCalloc(vars->sz_desc,XkbRF_VarDescRec);
1020 else if (vars->num_desc>=vars->sz_desc) {
1022 vars->desc= _XkbTypedRealloc(vars->desc,vars->sz_desc,XkbRF_VarDescRec);
1025 vars->sz_desc= vars->num_desc= 0;
1026 PR_DEBUG("Allocation failure in XkbcRF_AddVarDesc\n");
1029 vars->desc[vars->num_desc].name= NULL;
1030 vars->desc[vars->num_desc].desc= NULL;
1031 return &vars->desc[vars->num_desc++];
1035 XkbcRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars,XkbRF_VarDescPtr from)
1037 XkbRF_VarDescPtr nd;
1039 if ((nd=XkbcRF_AddVarDesc(vars))!=NULL) {
1040 nd->name= _XkbDupString(from->name);
1041 nd->desc= _XkbDupString(from->desc);
1046 XkbRF_DescribeVarsPtr
1047 XkbcRF_AddVarToDescribe(XkbRF_RulesPtr rules,char *name)
1049 if (rules->sz_extra<1) {
1050 rules->num_extra= 0;
1052 rules->extra_names= _XkbTypedCalloc(rules->sz_extra,char *);
1053 rules->extra= _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec);
1055 else if (rules->num_extra>=rules->sz_extra) {
1056 rules->sz_extra*= 2;
1057 rules->extra_names= _XkbTypedRealloc(rules->extra_names,rules->sz_extra,
1059 rules->extra=_XkbTypedRealloc(rules->extra, rules->sz_extra,
1060 XkbRF_DescribeVarsRec);
1062 if ((!rules->extra_names)||(!rules->extra)) {
1063 PR_DEBUG("allocation error in extra parts\n");
1064 rules->sz_extra= rules->num_extra= 0;
1065 rules->extra_names= NULL;
1069 rules->extra_names[rules->num_extra]= _XkbDupString(name);
1070 bzero(&rules->extra[rules->num_extra],sizeof(XkbRF_DescribeVarsRec));
1071 return &rules->extra[rules->num_extra++];
1075 XkbcRF_LoadDescriptions(FILE *file,XkbRF_RulesPtr rules)
1078 XkbRF_VarDescRec tmp;
1080 int len,headingtype,extra_ndx = 0;
1082 bzero((char *)&tmp, sizeof(XkbRF_VarDescRec));
1083 headingtype = HEAD_NONE;
1084 InitInputLine(&line);
1085 for ( ; GetInputLine(file,&line,False); line.num_line= 0) {
1086 if (line.line[0]=='!') {
1087 tok = strtok(&(line.line[1]), " \t");
1088 if (strcmp(tok,"model") == 0)
1089 headingtype = HEAD_MODEL;
1090 else if (_XkbStrCaseCmp(tok,"layout") == 0)
1091 headingtype = HEAD_LAYOUT;
1092 else if (_XkbStrCaseCmp(tok,"variant") == 0)
1093 headingtype = HEAD_VARIANT;
1094 else if (_XkbStrCaseCmp(tok,"option") == 0)
1095 headingtype = HEAD_OPTION;
1098 headingtype = HEAD_EXTRA;
1100 for (i=0;(i<rules->num_extra)&&(extra_ndx<0);i++) {
1101 if (_XkbStrCaseCmp(tok,rules->extra_names[i]))
1105 XkbRF_DescribeVarsPtr var;
1106 PR_DEBUG1("Extra heading \"%s\" encountered\n",tok);
1107 var= XkbcRF_AddVarToDescribe(rules,tok);
1109 extra_ndx= var-rules->extra;
1110 else headingtype= HEAD_NONE;
1116 if (headingtype == HEAD_NONE) {
1117 PR_DEBUG("Must have a heading before first line of data\n");
1118 PR_DEBUG("Illegal line of data ignored\n");
1122 len = strlen(line.line);
1123 if ((tmp.name= strtok(line.line, " \t")) == NULL) {
1124 PR_DEBUG("Huh? No token on line\n");
1125 PR_DEBUG("Illegal line of data ignored\n");
1128 if (strlen(tmp.name) == len) {
1129 PR_DEBUG("No description found\n");
1130 PR_DEBUG("Illegal line of data ignored\n");
1134 tok = line.line + strlen(tmp.name) + 1;
1135 while ((*tok!='\n')&&isspace(*tok))
1138 PR_DEBUG("No description found\n");
1139 PR_DEBUG("Illegal line of data ignored\n");
1143 switch (headingtype) {
1145 XkbcRF_AddVarDescCopy(&rules->models,&tmp);
1148 XkbcRF_AddVarDescCopy(&rules->layouts,&tmp);
1151 XkbcRF_AddVarDescCopy(&rules->variants,&tmp);
1154 XkbcRF_AddVarDescCopy(&rules->options,&tmp);
1157 XkbcRF_AddVarDescCopy(&rules->extra[extra_ndx],&tmp);
1161 FreeInputLine(&line);
1162 if ((rules->models.num_desc==0) && (rules->layouts.num_desc==0) &&
1163 (rules->variants.num_desc==0) && (rules->options.num_desc==0) &&
1164 (rules->num_extra==0)) {
1171 XkbcRF_LoadDescriptionsByName(char *base,char *locale,XkbRF_RulesPtr rules)
1177 if ((!base)||(!rules))
1180 if (strlen(base)+strlen(locale)+6 > PATH_MAX)
1182 sprintf(buf,"%s-%s.lst", base, locale);
1185 if (strlen(base)+5 > PATH_MAX)
1187 sprintf(buf,"%s.lst", base);
1190 file= fopen(buf, "r");
1191 if ((!file)&&(locale)) { /* fallback if locale was specified */
1192 sprintf(buf,"%s.lst", base);
1194 file= fopen(buf, "r");
1198 ok= XkbcRF_LoadDescriptions(file,rules);
1203 /***====================================================================***/
1206 XkbcRF_Load(char *base,char *locale,Bool wantDesc,Bool wantRules)
1208 XkbRF_RulesPtr rules;
1210 if ((!base)||((!wantDesc)&&(!wantRules)))
1212 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
1214 if (wantDesc&&(!XkbcRF_LoadDescriptionsByName(base,locale,rules))) {
1215 XkbcRF_Free(rules,True);
1218 if (wantRules&&(!XkbcRF_LoadRulesByName(base,locale,rules))) {
1219 XkbcRF_Free(rules,True);
1226 XkbcRF_Create(int szRules,int szExtra)
1228 XkbRF_RulesPtr rules;
1230 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
1233 rules->sz_rules= szRules;
1234 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
1235 if (!rules->rules) {
1241 rules->sz_extra= szExtra;
1242 rules->extra= _XkbTypedCalloc(rules->sz_extra,XkbRF_DescribeVarsRec);
1243 if (!rules->extra) {
1245 _XkbFree(rules->rules);
1253 /***====================================================================***/
1256 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
1260 for (i=0;i<var->num_desc;i++) {
1261 if (var->desc[i].name)
1262 _XkbFree(var->desc[i].name);
1263 if (var->desc[i].desc)
1264 _XkbFree(var->desc[i].desc);
1265 var->desc[i].name= var->desc[i].desc= NULL;
1268 _XkbFree(var->desc);
1274 XkbcRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
1278 XkbRF_GroupPtr group;
1282 XkbRF_ClearVarDescriptions(&rules->models);
1283 XkbRF_ClearVarDescriptions(&rules->layouts);
1284 XkbRF_ClearVarDescriptions(&rules->variants);
1285 XkbRF_ClearVarDescriptions(&rules->options);
1287 for (i = 0; i < rules->num_extra; i++) {
1288 XkbRF_ClearVarDescriptions(&rules->extra[i]);
1290 _XkbFree(rules->extra);
1291 rules->num_extra= rules->sz_extra= 0;
1295 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
1296 if (rule->model) _XkbFree(rule->model);
1297 if (rule->layout) _XkbFree(rule->layout);
1298 if (rule->variant) _XkbFree(rule->variant);
1299 if (rule->option) _XkbFree(rule->option);
1300 if (rule->keycodes) _XkbFree(rule->keycodes);
1301 if (rule->symbols) _XkbFree(rule->symbols);
1302 if (rule->types) _XkbFree(rule->types);
1303 if (rule->compat) _XkbFree(rule->compat);
1304 if (rule->geometry) _XkbFree(rule->geometry);
1305 if (rule->keymap) _XkbFree(rule->keymap);
1306 bzero((char *)rule,sizeof(XkbRF_RuleRec));
1308 _XkbFree(rules->rules);
1309 rules->num_rules= rules->sz_rules= 0;
1313 if (rules->groups) {
1314 for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) {
1315 if (group->name) _XkbFree(group->name);
1316 if (group->words) _XkbFree(group->words);
1318 _XkbFree(rules->groups);
1319 rules->num_groups= 0;
1320 rules->groups= NULL;