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 ********************************************************/
30 #include "X11/extensions/XKBcommon.h"
31 #include "XKBcommonint.h"
33 #ifdef HAVE_DIX_CONFIG_H
34 #include <dix-config.h>
35 #elif defined(HAVE_CONFIG_H)
43 #define X_INCLUDE_STRING_H
44 #define XOS_USE_NO_LOCKING
45 #include <X11/Xos_r.h>
47 #include <X11/Xproto.h>
50 #include <X11/Xfuncs.h>
53 #define PR_DEBUG(s) fprintf(stderr,s)
54 #define PR_DEBUG1(s,a) fprintf(stderr,s,a)
55 #define PR_DEBUG2(s,a,b) fprintf(stderr,s,a,b)
58 #define PR_DEBUG1(s,a)
59 #define PR_DEBUG2(s,a,b)
62 /***====================================================================***/
64 #define DFLT_LINE_SIZE 128
70 char buf[DFLT_LINE_SIZE];
75 InitInputLine(InputLine *line)
79 line->sz_line= DFLT_LINE_SIZE;
80 line->line= line->buf;
85 FreeInputLine(InputLine *line)
87 if (line->line!=line->buf)
91 line->sz_line= DFLT_LINE_SIZE;
92 line->line= line->buf;
97 InputLineAddChar(InputLine *line,int ch)
99 if (line->num_line>=line->sz_line) {
100 if (line->line==line->buf) {
101 line->line= (char *)_XkbAlloc(line->sz_line*2);
102 memcpy(line->line,line->buf,line->sz_line);
105 line->line=(char *)_XkbRealloc((char *)line->line,line->sz_line*2);
109 line->line[line->num_line++]= ch;
113 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
114 (int)((l)->line[(l)->num_line++]= (c)):\
115 InputLineAddChar(l,c))
118 GetInputLine(FILE *file,InputLine *line,Bool checkbang)
121 Bool endOfFile,spacePending,slashPending,inComment;
124 while ((!endOfFile)&&(line->num_line==0)) {
125 spacePending= slashPending= inComment= False;
126 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
128 if ((ch=getc(file))==EOF)
148 else if (slashPending) {
157 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
162 if ((ch!='\n')&&(line->num_line>0))
171 if (checkbang && ch=='!') {
172 if (line->num_line!=0) {
173 PR_DEBUG("The '!' legal only at start of line\n");
174 PR_DEBUG("Line containing '!' ignored\n");
186 /* else line->num_line++;*/
188 if ((line->num_line==0)&&(endOfFile))
194 /***====================================================================***/
208 #define PART_MASK 0x000F
209 #define COMPONENT_MASK 0x03F0
211 static char * cname[MAX_WORDS] = {
212 "model", "layout", "variant", "option",
213 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
216 typedef struct _RemapSpec {
225 typedef struct _FileSpec {
226 char * name[MAX_WORDS];
227 struct _FileSpec * pending;
232 char * layout[XkbNumKbdGroups+1];
233 char * variant[XkbNumKbdGroups+1];
235 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
237 #define NDX_BUFF_SIZE 4
239 /***====================================================================***/
242 get_index(char *str, int *ndx)
244 char ndx_buf[NDX_BUFF_SIZE];
252 end = strchr(str, ']');
257 if ( (end - str) >= NDX_BUFF_SIZE) {
261 strncpy(ndx_buf, str, end - str);
262 ndx_buf[end - str] = '\0';
263 *ndx = atoi(ndx_buf);
268 SetUpRemap(InputLine *line,RemapSpec *remap)
271 unsigned present, l_ndx_present, v_ndx_present;
274 _Xstrtokparams strtok_buf;
280 l_ndx_present = v_ndx_present = present= 0;
283 bzero((char *)remap,sizeof(RemapSpec));
285 while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
290 if (strcmp(tok,"=")==0)
292 for (i=0;i<MAX_WORDS;i++) {
293 len = strlen(cname[i]);
294 if (strncmp(cname[i],tok,len)==0) {
295 if(strlen(tok) > len) {
296 char *end = get_index(tok+len, &ndx);
297 if ((i != LAYOUT && i != VARIANT) ||
298 *end != '\0' || ndx == -1)
300 if (ndx < 1 || ndx > XkbNumKbdGroups) {
301 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
302 PR_DEBUG1("Index must be in range 1..%d\n",
312 if (present&(1<<i)) {
313 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
314 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
315 PR_DEBUG1("Component \"%s\" listed twice\n",tok);
316 PR_DEBUG("Second definition ignored\n");
322 l_ndx_present |= 1 << ndx;
324 v_ndx_present |= 1 << ndx;
325 remap->remap[remap->num_remap].word= i;
326 remap->remap[remap->num_remap++].index= ndx;
332 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
336 if ((present&PART_MASK)==0) {
338 unsigned mask= PART_MASK;
339 fprintf(stderr,"Mapping needs at least one of ");
340 for (i=0; (i<MAX_WORDS); i++) {
343 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
344 else fprintf(stderr,"or \"%s\"\n",cname[i]);
347 fprintf(stderr,"Illegal mapping ignored\n");
352 if ((present&COMPONENT_MASK)==0) {
353 PR_DEBUG("Mapping needs at least one component\n");
354 PR_DEBUG("Illegal mapping ignored\n");
358 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
359 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
360 PR_DEBUG("Keymap cannot appear with other components\n");
361 PR_DEBUG("Illegal mapping ignored\n");
370 MatchOneOf(char *wanted,char *vals_defined)
373 int want_len= strlen(wanted);
375 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
377 next= strchr(str,',');
385 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
391 /***====================================================================***/
394 CheckLine( InputLine * line,
397 XkbRF_GroupPtr group)
400 register int nread, i;
402 _Xstrtokparams strtok_buf;
405 if (line->line[0]=='!') {
406 if (line->line[1] == '$' ||
407 (line->line[1] == ' ' && line->line[2] == '$')) {
408 char *gname = strchr(line->line, '$');
409 char *words = strchr(gname, ' ');
413 for (; *words; words++) {
414 if (*words != '=' && *words != ' ')
419 group->name = _XkbDupString(gname);
420 group->words = _XkbDupString(words);
421 for (i = 1, words = group->words; *words; words++) {
422 if ( *words == ' ') {
430 SetUpRemap(line,remap);
435 if (remap->num_remap==0) {
436 PR_DEBUG("Must have a mapping before first line of data\n");
437 PR_DEBUG("Illegal line of data ignored\n");
440 bzero((char *)&tmp,sizeof(FileSpec));
442 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
444 if (strcmp(tok,"=")==0) {
448 if (nread>remap->num_remap) {
449 PR_DEBUG("Too many words on a line\n");
450 PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
453 tmp.name[remap->remap[nread].word]= tok;
454 if (*tok == '+' || *tok == '|')
457 if (nread<remap->num_remap) {
458 PR_DEBUG1("Too few words on a line: %s\n", line->line);
459 PR_DEBUG("line ignored\n");
464 rule->number = remap->number;
465 if (tmp.name[OPTION])
466 rule->flags|= XkbRF_Option;
468 rule->flags|= XkbRF_Append;
470 rule->flags|= XkbRF_Normal;
471 rule->model= _XkbDupString(tmp.name[MODEL]);
472 rule->layout= _XkbDupString(tmp.name[LAYOUT]);
473 rule->variant= _XkbDupString(tmp.name[VARIANT]);
474 rule->option= _XkbDupString(tmp.name[OPTION]);
476 rule->keycodes= _XkbDupString(tmp.name[KEYCODES]);
477 rule->symbols= _XkbDupString(tmp.name[SYMBOLS]);
478 rule->types= _XkbDupString(tmp.name[TYPES]);
479 rule->compat= _XkbDupString(tmp.name[COMPAT]);
480 rule->geometry= _XkbDupString(tmp.name[GEOMETRY]);
481 rule->keymap= _XkbDupString(tmp.name[KEYMAP]);
483 rule->layout_num = rule->variant_num = 0;
484 for (i = 0; i < nread; i++) {
485 if (remap->remap[i].index) {
486 if (remap->remap[i].word == LAYOUT)
487 rule->layout_num = remap->remap[i].index;
488 if (remap->remap[i].word == VARIANT)
489 rule->variant_num = remap->remap[i].index;
496 _Concat(char *str1,char *str2)
500 if ((!str1)||(!str2))
502 len= strlen(str1)+strlen(str2)+1;
503 str1= _XkbTypedRealloc(str1,len,char);
510 squeeze_spaces(char *p1)
513 for (p2 = p1; *p2; p2++) {
515 if (*p1 != ' ') p1++;
521 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
524 bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec));
525 mdefs->model = defs->model;
526 mdefs->options = _XkbDupString(defs->options);
527 if (mdefs->options) squeeze_spaces(mdefs->options);
530 if (!strchr(defs->layout, ',')) {
531 mdefs->layout[0] = defs->layout;
535 mdefs->layout[1] = _XkbDupString(defs->layout);
536 if (mdefs->layout[1] == NULL)
538 squeeze_spaces(mdefs->layout[1]);
539 p = mdefs->layout[1];
540 for (i = 2; i <= XkbNumKbdGroups; i++) {
541 if ((p = strchr(p, ','))) {
543 mdefs->layout[i] = p;
548 if (p && (p = strchr(p, ',')))
554 if (!strchr(defs->variant, ',')) {
555 mdefs->variant[0] = defs->variant;
559 mdefs->variant[1] = _XkbDupString(defs->variant);
560 if (mdefs->variant[1] == NULL)
562 squeeze_spaces(mdefs->variant[1]);
563 p = mdefs->variant[1];
564 for (i = 2; i <= XkbNumKbdGroups; i++) {
565 if ((p = strchr(p, ','))) {
567 mdefs->variant[i] = p;
572 if (p && (p = strchr(p, ',')))
580 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
582 if (defs->options) _XkbFree(defs->options);
583 if (defs->layout[1]) _XkbFree(defs->layout[1]);
584 if (defs->variant[1]) _XkbFree(defs->variant[1]);
588 Apply(char *src, char **dst)
591 if (*src == '+' || *src == '!') {
592 *dst= _Concat(*dst, src);
595 *dst= _XkbDupString(src);
601 XkbRF_ApplyRule( XkbRF_RulePtr rule,
602 XkbComponentNamesPtr names)
604 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
606 Apply(rule->keycodes, &names->keycodes);
607 Apply(rule->symbols, &names->symbols);
608 Apply(rule->types, &names->types);
609 Apply(rule->compat, &names->compat);
610 Apply(rule->geometry, &names->geometry);
611 Apply(rule->keymap, &names->keymap);
615 CheckGroup( XkbRF_RulesPtr rules,
621 XkbRF_GroupPtr group;
623 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
624 if (! strcmp(group->name, group_name)) {
628 if (i == rules->num_groups)
630 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
631 if (! strcmp(p, name)) {
639 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
640 XkbRF_MultiDefsPtr mdefs,
641 XkbComponentNamesPtr names,
642 XkbRF_RulesPtr rules)
644 Bool pending = False;
646 if (rule->model != NULL) {
647 if(mdefs->model == NULL)
649 if (strcmp(rule->model, "*") == 0) {
652 if (rule->model[0] == '$') {
653 if (!CheckGroup(rules, rule->model, mdefs->model))
656 if (strcmp(rule->model, mdefs->model) != 0)
661 if (rule->option != NULL) {
662 if (mdefs->options == NULL)
664 if ((!MatchOneOf(rule->option,mdefs->options)))
668 if (rule->layout != NULL) {
669 if(mdefs->layout[rule->layout_num] == NULL ||
670 *mdefs->layout[rule->layout_num] == '\0')
672 if (strcmp(rule->layout, "*") == 0) {
675 if (rule->layout[0] == '$') {
676 if (!CheckGroup(rules, rule->layout,
677 mdefs->layout[rule->layout_num]))
680 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
685 if (rule->variant != NULL) {
686 if (mdefs->variant[rule->variant_num] == NULL ||
687 *mdefs->variant[rule->variant_num] == '\0')
689 if (strcmp(rule->variant, "*") == 0) {
692 if (rule->variant[0] == '$') {
693 if (!CheckGroup(rules, rule->variant,
694 mdefs->variant[rule->variant_num]))
697 if (strcmp(rule->variant,
698 mdefs->variant[rule->variant_num]) != 0)
704 rule->flags|= XkbRF_PendingMatch;
707 /* exact match, apply it now */
708 XkbRF_ApplyRule(rule,names);
713 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
718 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
719 rule->flags&= ~XkbRF_PendingMatch;
724 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names)
729 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
730 if ((rule->flags&XkbRF_PendingMatch)==0)
732 XkbRF_ApplyRule(rule,names);
737 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
738 XkbRF_MultiDefsPtr mdefs,
739 XkbComponentNamesPtr names,
746 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
747 if ((rule->flags & flags) != flags)
749 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
750 if (skip && !(flags & XkbRF_Option)) {
751 for ( ;(i < rules->num_rules) && (rule->number == skip);
758 /***====================================================================***/
761 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
763 char *str, *outstr, *orig, *var;
767 str= index(name,'%');
774 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
783 str = get_index(var + 1, &ndx);
785 str = index(str,'%');
788 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
789 len+= strlen(mdefs->layout[ndx])+extra_len;
790 else if ((*var=='m')&&mdefs->model)
791 len+= strlen(mdefs->model)+extra_len;
792 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
793 len+= strlen(mdefs->variant[ndx])+extra_len;
794 if ((pfx=='(')&&(*str==')')) {
797 str= index(&str[0],'%');
799 name= (char *)_XkbAlloc(len+1);
808 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
818 str = get_index(var + 1, &ndx);
822 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
823 if (pfx) *outstr++= pfx;
824 strcpy(outstr,mdefs->layout[ndx]);
825 outstr+= strlen(mdefs->layout[ndx]);
826 if (sfx) *outstr++= sfx;
828 else if ((*var=='m')&&(mdefs->model)) {
829 if (pfx) *outstr++= pfx;
830 strcpy(outstr,mdefs->model);
831 outstr+= strlen(mdefs->model);
832 if (sfx) *outstr++= sfx;
834 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
835 if (pfx) *outstr++= pfx;
836 strcpy(outstr,mdefs->variant[ndx]);
837 outstr+= strlen(mdefs->variant[ndx]);
838 if (sfx) *outstr++= sfx;
840 if ((pfx=='(')&&(*str==')'))
853 /***====================================================================***/
856 XkbcRF_GetComponents( XkbRF_RulesPtr rules,
857 XkbRF_VarDefsPtr defs,
858 XkbComponentNamesPtr names)
860 XkbRF_MultiDefsRec mdefs;
862 MakeMultiDefs(&mdefs, defs);
864 bzero((char *)names,sizeof(XkbComponentNamesRec));
865 XkbRF_ClearPartialMatches(rules);
866 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
867 XkbRF_ApplyPartialMatches(rules, names);
868 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
869 XkbRF_ApplyPartialMatches(rules, names);
870 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
871 XkbRF_ApplyPartialMatches(rules, names);
874 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
876 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
878 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
880 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
882 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
884 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
886 FreeMultiDefs(&mdefs);
887 return (names->keycodes && names->symbols && names->types &&
888 names->compat && names->geometry ) || names->keymap;
892 XkbcRF_AddRule(XkbRF_RulesPtr rules)
894 if (rules->sz_rules<1) {
897 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
899 else if (rules->num_rules>=rules->sz_rules) {
901 rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
905 rules->sz_rules= rules->num_rules= 0;
907 fprintf(stderr,"Allocation failure in XkbcRF_AddRule\n");
911 bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec));
912 return &rules->rules[rules->num_rules++];
916 XkbcRF_AddGroup(XkbRF_RulesPtr rules)
918 if (rules->sz_groups<1) {
919 rules->sz_groups= 16;
920 rules->num_groups= 0;
921 rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
923 else if (rules->num_groups >= rules->sz_groups) {
924 rules->sz_groups *= 2;
925 rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups,
928 if (!rules->groups) {
929 rules->sz_groups= rules->num_groups= 0;
933 bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec));
934 return &rules->groups[rules->num_groups++];
938 XkbcRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
942 XkbRF_RuleRec trule,*rule;
943 XkbRF_GroupRec tgroup,*group;
945 if (!(rules && file))
947 bzero((char *)&remap,sizeof(RemapSpec));
948 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
949 InitInputLine(&line);
950 while (GetInputLine(file,&line,True)) {
951 if (CheckLine(&line,&remap,&trule,&tgroup)) {
953 if ((group= XkbcRF_AddGroup(rules))!=NULL) {
955 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
958 if ((rule= XkbcRF_AddRule(rules))!=NULL) {
960 bzero((char *)&trule,sizeof(XkbRF_RuleRec));
966 FreeInputLine(&line);
971 XkbcRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules)
977 if ((!base)||(!rules))
980 if (strlen(base)+strlen(locale)+2 > PATH_MAX)
982 sprintf(buf,"%s-%s", base, locale);
985 if (strlen(base)+1 > PATH_MAX)
990 file= fopen(buf, "r");
991 if ((!file)&&(locale)) { /* fallback if locale was specified */
993 file= fopen(buf, "r");
997 ok= XkbcRF_LoadRules(file,rules);
1002 /***====================================================================***/
1005 #define HEAD_MODEL 1
1006 #define HEAD_LAYOUT 2
1007 #define HEAD_VARIANT 3
1008 #define HEAD_OPTION 4
1009 #define HEAD_EXTRA 5
1012 XkbcRF_AddVarDesc(XkbRF_DescribeVarsPtr vars)
1014 if (vars->sz_desc<1) {
1017 vars->desc= _XkbTypedCalloc(vars->sz_desc,XkbRF_VarDescRec);
1019 else if (vars->num_desc>=vars->sz_desc) {
1021 vars->desc= _XkbTypedRealloc(vars->desc,vars->sz_desc,XkbRF_VarDescRec);
1024 vars->sz_desc= vars->num_desc= 0;
1025 PR_DEBUG("Allocation failure in XkbcRF_AddVarDesc\n");
1028 vars->desc[vars->num_desc].name= NULL;
1029 vars->desc[vars->num_desc].desc= NULL;
1030 return &vars->desc[vars->num_desc++];
1034 XkbcRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars,XkbRF_VarDescPtr from)
1036 XkbRF_VarDescPtr nd;
1038 if ((nd=XkbcRF_AddVarDesc(vars))!=NULL) {
1039 nd->name= _XkbDupString(from->name);
1040 nd->desc= _XkbDupString(from->desc);
1045 XkbRF_DescribeVarsPtr
1046 XkbcRF_AddVarToDescribe(XkbRF_RulesPtr rules,char *name)
1048 if (rules->sz_extra<1) {
1049 rules->num_extra= 0;
1051 rules->extra_names= _XkbTypedCalloc(rules->sz_extra,char *);
1052 rules->extra= _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec);
1054 else if (rules->num_extra>=rules->sz_extra) {
1055 rules->sz_extra*= 2;
1056 rules->extra_names= _XkbTypedRealloc(rules->extra_names,rules->sz_extra,
1058 rules->extra=_XkbTypedRealloc(rules->extra, rules->sz_extra,
1059 XkbRF_DescribeVarsRec);
1061 if ((!rules->extra_names)||(!rules->extra)) {
1062 PR_DEBUG("allocation error in extra parts\n");
1063 rules->sz_extra= rules->num_extra= 0;
1064 rules->extra_names= NULL;
1068 rules->extra_names[rules->num_extra]= _XkbDupString(name);
1069 bzero(&rules->extra[rules->num_extra],sizeof(XkbRF_DescribeVarsRec));
1070 return &rules->extra[rules->num_extra++];
1074 XkbcRF_LoadDescriptions(FILE *file,XkbRF_RulesPtr rules)
1077 XkbRF_VarDescRec tmp;
1079 int len,headingtype,extra_ndx = 0;
1081 bzero((char *)&tmp, sizeof(XkbRF_VarDescRec));
1082 headingtype = HEAD_NONE;
1083 InitInputLine(&line);
1084 for ( ; GetInputLine(file,&line,False); line.num_line= 0) {
1085 if (line.line[0]=='!') {
1086 tok = strtok(&(line.line[1]), " \t");
1087 if (strcmp(tok,"model") == 0)
1088 headingtype = HEAD_MODEL;
1089 else if (_XkbStrCaseCmp(tok,"layout") == 0)
1090 headingtype = HEAD_LAYOUT;
1091 else if (_XkbStrCaseCmp(tok,"variant") == 0)
1092 headingtype = HEAD_VARIANT;
1093 else if (_XkbStrCaseCmp(tok,"option") == 0)
1094 headingtype = HEAD_OPTION;
1097 headingtype = HEAD_EXTRA;
1099 for (i=0;(i<rules->num_extra)&&(extra_ndx<0);i++) {
1100 if (_XkbStrCaseCmp(tok,rules->extra_names[i]))
1104 XkbRF_DescribeVarsPtr var;
1105 PR_DEBUG1("Extra heading \"%s\" encountered\n",tok);
1106 var= XkbcRF_AddVarToDescribe(rules,tok);
1108 extra_ndx= var-rules->extra;
1109 else headingtype= HEAD_NONE;
1115 if (headingtype == HEAD_NONE) {
1116 PR_DEBUG("Must have a heading before first line of data\n");
1117 PR_DEBUG("Illegal line of data ignored\n");
1121 len = strlen(line.line);
1122 if ((tmp.name= strtok(line.line, " \t")) == NULL) {
1123 PR_DEBUG("Huh? No token on line\n");
1124 PR_DEBUG("Illegal line of data ignored\n");
1127 if (strlen(tmp.name) == len) {
1128 PR_DEBUG("No description found\n");
1129 PR_DEBUG("Illegal line of data ignored\n");
1133 tok = line.line + strlen(tmp.name) + 1;
1134 while ((*tok!='\n')&&isspace(*tok))
1137 PR_DEBUG("No description found\n");
1138 PR_DEBUG("Illegal line of data ignored\n");
1142 switch (headingtype) {
1144 XkbcRF_AddVarDescCopy(&rules->models,&tmp);
1147 XkbcRF_AddVarDescCopy(&rules->layouts,&tmp);
1150 XkbcRF_AddVarDescCopy(&rules->variants,&tmp);
1153 XkbcRF_AddVarDescCopy(&rules->options,&tmp);
1156 XkbcRF_AddVarDescCopy(&rules->extra[extra_ndx],&tmp);
1160 FreeInputLine(&line);
1161 if ((rules->models.num_desc==0) && (rules->layouts.num_desc==0) &&
1162 (rules->variants.num_desc==0) && (rules->options.num_desc==0) &&
1163 (rules->num_extra==0)) {
1170 XkbcRF_LoadDescriptionsByName(char *base,char *locale,XkbRF_RulesPtr rules)
1176 if ((!base)||(!rules))
1179 if (strlen(base)+strlen(locale)+6 > PATH_MAX)
1181 sprintf(buf,"%s-%s.lst", base, locale);
1184 if (strlen(base)+5 > PATH_MAX)
1186 sprintf(buf,"%s.lst", base);
1189 file= fopen(buf, "r");
1190 if ((!file)&&(locale)) { /* fallback if locale was specified */
1191 sprintf(buf,"%s.lst", base);
1193 file= fopen(buf, "r");
1197 ok= XkbcRF_LoadDescriptions(file,rules);
1202 /***====================================================================***/
1205 XkbcRF_Load(char *base,char *locale,Bool wantDesc,Bool wantRules)
1207 XkbRF_RulesPtr rules;
1209 if ((!base)||((!wantDesc)&&(!wantRules)))
1211 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
1213 if (wantDesc&&(!XkbcRF_LoadDescriptionsByName(base,locale,rules))) {
1214 XkbcRF_Free(rules,True);
1217 if (wantRules&&(!XkbcRF_LoadRulesByName(base,locale,rules))) {
1218 XkbcRF_Free(rules,True);
1225 XkbcRF_Create(int szRules,int szExtra)
1227 XkbRF_RulesPtr rules;
1229 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
1232 rules->sz_rules= szRules;
1233 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
1234 if (!rules->rules) {
1240 rules->sz_extra= szExtra;
1241 rules->extra= _XkbTypedCalloc(rules->sz_extra,XkbRF_DescribeVarsRec);
1242 if (!rules->extra) {
1244 _XkbFree(rules->rules);
1252 /***====================================================================***/
1255 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
1259 for (i=0;i<var->num_desc;i++) {
1260 if (var->desc[i].name)
1261 _XkbFree(var->desc[i].name);
1262 if (var->desc[i].desc)
1263 _XkbFree(var->desc[i].desc);
1264 var->desc[i].name= var->desc[i].desc= NULL;
1267 _XkbFree(var->desc);
1273 XkbcRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
1277 XkbRF_GroupPtr group;
1281 XkbRF_ClearVarDescriptions(&rules->models);
1282 XkbRF_ClearVarDescriptions(&rules->layouts);
1283 XkbRF_ClearVarDescriptions(&rules->variants);
1284 XkbRF_ClearVarDescriptions(&rules->options);
1286 for (i = 0; i < rules->num_extra; i++) {
1287 XkbRF_ClearVarDescriptions(&rules->extra[i]);
1289 _XkbFree(rules->extra);
1290 rules->num_extra= rules->sz_extra= 0;
1294 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
1295 if (rule->model) _XkbFree(rule->model);
1296 if (rule->layout) _XkbFree(rule->layout);
1297 if (rule->variant) _XkbFree(rule->variant);
1298 if (rule->option) _XkbFree(rule->option);
1299 if (rule->keycodes) _XkbFree(rule->keycodes);
1300 if (rule->symbols) _XkbFree(rule->symbols);
1301 if (rule->types) _XkbFree(rule->types);
1302 if (rule->compat) _XkbFree(rule->compat);
1303 if (rule->geometry) _XkbFree(rule->geometry);
1304 if (rule->keymap) _XkbFree(rule->keymap);
1305 bzero((char *)rule,sizeof(XkbRF_RuleRec));
1307 _XkbFree(rules->rules);
1308 rules->num_rules= rules->sz_rules= 0;
1312 if (rules->groups) {
1313 for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) {
1314 if (group->name) _XkbFree(group->name);
1315 if (group->words) _XkbFree(group->words);
1317 _XkbFree(rules->groups);
1318 rules->num_groups= 0;
1319 rules->groups= NULL;