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 ********************************************************/
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
29 #elif defined(HAVE_CONFIG_H)
37 #define X_INCLUDE_STRING_H
38 #define XOS_USE_NO_LOCKING
39 #include <X11/Xos_r.h>
43 #include <X11/Xproto.h>
46 #include <X11/Xfuncs.h>
47 #include <X11/Xatom.h>
48 #include <X11/keysym.h>
49 #include <X11/XKBlib.h>
50 #include <X11/extensions/XKBgeom.h>
51 #include "XKMformat.h"
52 #include "XKBfileInt.h"
57 #include <X11/Xproto.h>
60 #include <X11/Xfuncs.h>
61 #include <X11/Xatom.h>
62 #include <X11/keysym.h>
66 #include <X11/extensions/XKBstr.h>
67 #define XKBSRV_NEED_FILE_FUNCS
68 #include <X11/extensions/XKBsrv.h>
73 #define PR_DEBUG(s) fprintf(stderr,s)
74 #define PR_DEBUG1(s,a) fprintf(stderr,s,a)
75 #define PR_DEBUG2(s,a,b) fprintf(stderr,s,a,b)
78 #define PR_DEBUG1(s,a)
79 #define PR_DEBUG2(s,a,b)
82 /***====================================================================***/
84 #define DFLT_LINE_SIZE 128
90 char buf[DFLT_LINE_SIZE];
95 InitInputLine(InputLine *line)
99 line->sz_line= DFLT_LINE_SIZE;
100 line->line= line->buf;
105 FreeInputLine(InputLine *line)
107 if (line->line!=line->buf)
108 _XkbFree(line->line);
111 line->sz_line= DFLT_LINE_SIZE;
112 line->line= line->buf;
117 InputLineAddChar(InputLine *line,int ch)
119 if (line->num_line>=line->sz_line) {
120 if (line->line==line->buf) {
121 line->line= (char *)_XkbAlloc(line->sz_line*2);
122 memcpy(line->line,line->buf,line->sz_line);
125 line->line=(char *)_XkbRealloc((char *)line->line,line->sz_line*2);
129 line->line[line->num_line++]= ch;
133 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\
134 (int)((l)->line[(l)->num_line++]= (c)):\
135 InputLineAddChar(l,c))
137 #ifdef HAVE_UNLOCKED_STDIO
139 #define getc(x) getc_unlocked(x)
141 #define flockfile(x) do {} while (0)
142 #define funlockfile(x) do {} while (0)
146 GetInputLine(FILE *file,InputLine *line,Bool checkbang)
149 Bool endOfFile,spacePending,slashPending,inComment;
153 while ((!endOfFile)&&(line->num_line==0)) {
154 spacePending= slashPending= inComment= False;
155 while (((ch=getc(file))!='\n')&&(ch!=EOF)) {
157 if ((ch=getc(file))==EOF)
177 else if (slashPending) {
186 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) {
191 if ((ch!='\n')&&(line->num_line>0))
200 if (checkbang && ch=='!') {
201 if (line->num_line!=0) {
202 PR_DEBUG("The '!' legal only at start of line\n");
203 PR_DEBUG("Line containing '!' ignored\n");
215 /* else line->num_line++;*/
218 if ((line->num_line==0)&&(endOfFile))
224 /***====================================================================***/
238 #define PART_MASK 0x000F
239 #define COMPONENT_MASK 0x03F0
241 static const char * cname[MAX_WORDS] = {
242 "model", "layout", "variant", "option",
243 "keycodes", "symbols", "types", "compat", "geometry", "keymap"
246 typedef struct _RemapSpec {
255 typedef struct _FileSpec {
256 char * name[MAX_WORDS];
257 struct _FileSpec * pending;
262 char * layout[XkbNumKbdGroups+1];
263 char * variant[XkbNumKbdGroups+1];
265 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
267 #define NDX_BUFF_SIZE 4
269 /***====================================================================***/
272 get_index(char *str, int *ndx)
274 char ndx_buf[NDX_BUFF_SIZE];
282 end = strchr(str, ']');
287 if ( (end - str) >= NDX_BUFF_SIZE) {
291 strncpy(ndx_buf, str, end - str);
292 ndx_buf[end - str] = '\0';
293 *ndx = atoi(ndx_buf);
298 SetUpRemap(InputLine *line,RemapSpec *remap)
301 unsigned present, l_ndx_present, v_ndx_present;
304 _Xstrtokparams strtok_buf;
310 l_ndx_present = v_ndx_present = present= 0;
313 bzero((char *)remap,sizeof(RemapSpec));
315 while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) {
320 if (strcmp(tok,"=")==0)
322 for (i=0;i<MAX_WORDS;i++) {
323 len = strlen(cname[i]);
324 if (strncmp(cname[i],tok,len)==0) {
325 if(strlen(tok) > len) {
326 char *end = get_index(tok+len, &ndx);
327 if ((i != LAYOUT && i != VARIANT) ||
328 *end != '\0' || ndx == -1)
330 if (ndx < 1 || ndx > XkbNumKbdGroups) {
331 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx);
332 PR_DEBUG1("Index must be in range 1..%d\n",
342 if (present&(1<<i)) {
343 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) ||
344 (i == VARIANT && v_ndx_present&(1<<ndx)) ) {
345 PR_DEBUG1("Component \"%s\" listed twice\n",tok);
346 PR_DEBUG("Second definition ignored\n");
352 l_ndx_present |= 1 << ndx;
354 v_ndx_present |= 1 << ndx;
355 remap->remap[remap->num_remap].word= i;
356 remap->remap[remap->num_remap++].index= ndx;
362 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok);
366 if ((present&PART_MASK)==0) {
368 unsigned mask= PART_MASK;
369 fprintf(stderr,"Mapping needs at least one of ");
370 for (i=0; (i<MAX_WORDS); i++) {
373 if (mask) fprintf(stderr,"\"%s,\" ",cname[i]);
374 else fprintf(stderr,"or \"%s\"\n",cname[i]);
377 fprintf(stderr,"Illegal mapping ignored\n");
382 if ((present&COMPONENT_MASK)==0) {
383 PR_DEBUG("Mapping needs at least one component\n");
384 PR_DEBUG("Illegal mapping ignored\n");
388 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&&
389 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) {
390 PR_DEBUG("Keymap cannot appear with other components\n");
391 PR_DEBUG("Illegal mapping ignored\n");
400 MatchOneOf(char *wanted,char *vals_defined)
403 int want_len= strlen(wanted);
405 for (str=vals_defined,next=NULL;str!=NULL;str=next) {
407 next= strchr(str,',');
415 if ((len==want_len)&&(strncmp(wanted,str,len)==0))
421 /***====================================================================***/
424 CheckLine( InputLine * line,
427 XkbRF_GroupPtr group)
430 register int nread, i;
432 _Xstrtokparams strtok_buf;
435 if (line->line[0]=='!') {
436 if (line->line[1] == '$' ||
437 (line->line[1] == ' ' && line->line[2] == '$')) {
438 char *gname = strchr(line->line, '$');
439 char *words = strchr(gname, ' ');
443 for (; *words; words++) {
444 if (*words != '=' && *words != ' ')
449 group->name = _XkbDupString(gname);
450 group->words = _XkbDupString(words);
451 for (i = 1, words = group->words; *words; words++) {
452 if ( *words == ' ') {
460 SetUpRemap(line,remap);
465 if (remap->num_remap==0) {
466 PR_DEBUG("Must have a mapping before first line of data\n");
467 PR_DEBUG("Illegal line of data ignored\n");
470 bzero((char *)&tmp,sizeof(FileSpec));
472 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) {
474 if (strcmp(tok,"=")==0) {
478 if (nread>remap->num_remap) {
479 PR_DEBUG("Too many words on a line\n");
480 PR_DEBUG1("Extra word \"%s\" ignored\n",tok);
483 tmp.name[remap->remap[nread].word]= tok;
484 if (*tok == '+' || *tok == '|')
487 if (nread<remap->num_remap) {
488 PR_DEBUG1("Too few words on a line: %s\n", line->line);
489 PR_DEBUG("line ignored\n");
494 rule->number = remap->number;
495 if (tmp.name[OPTION])
496 rule->flags|= XkbRF_Option;
498 rule->flags|= XkbRF_Append;
500 rule->flags|= XkbRF_Normal;
501 rule->model= _XkbDupString(tmp.name[MODEL]);
502 rule->layout= _XkbDupString(tmp.name[LAYOUT]);
503 rule->variant= _XkbDupString(tmp.name[VARIANT]);
504 rule->option= _XkbDupString(tmp.name[OPTION]);
506 rule->keycodes= _XkbDupString(tmp.name[KEYCODES]);
507 rule->symbols= _XkbDupString(tmp.name[SYMBOLS]);
508 rule->types= _XkbDupString(tmp.name[TYPES]);
509 rule->compat= _XkbDupString(tmp.name[COMPAT]);
510 rule->geometry= _XkbDupString(tmp.name[GEOMETRY]);
511 rule->keymap= _XkbDupString(tmp.name[KEYMAP]);
513 rule->layout_num = rule->variant_num = 0;
514 for (i = 0; i < nread; i++) {
515 if (remap->remap[i].index) {
516 if (remap->remap[i].word == LAYOUT)
517 rule->layout_num = remap->remap[i].index;
518 if (remap->remap[i].word == VARIANT)
519 rule->variant_num = remap->remap[i].index;
526 _Concat(char *str1,char *str2)
530 if ((!str1)||(!str2))
532 len= strlen(str1)+strlen(str2)+1;
533 str1= _XkbTypedRealloc(str1,len,char);
540 squeeze_spaces(char *p1)
543 for (p2 = p1; *p2; p2++) {
545 if (*p1 != ' ') p1++;
551 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
554 bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec));
555 mdefs->model = defs->model;
556 mdefs->options = _XkbDupString(defs->options);
557 if (mdefs->options) squeeze_spaces(mdefs->options);
560 if (!strchr(defs->layout, ',')) {
561 mdefs->layout[0] = defs->layout;
565 mdefs->layout[1] = _XkbDupString(defs->layout);
566 if (mdefs->layout[1] == NULL)
568 squeeze_spaces(mdefs->layout[1]);
569 p = mdefs->layout[1];
570 for (i = 2; i <= XkbNumKbdGroups; i++) {
571 if ((p = strchr(p, ','))) {
573 mdefs->layout[i] = p;
578 if (p && (p = strchr(p, ',')))
584 if (!strchr(defs->variant, ',')) {
585 mdefs->variant[0] = defs->variant;
589 mdefs->variant[1] = _XkbDupString(defs->variant);
590 if (mdefs->variant[1] == NULL)
592 squeeze_spaces(mdefs->variant[1]);
593 p = mdefs->variant[1];
594 for (i = 2; i <= XkbNumKbdGroups; i++) {
595 if ((p = strchr(p, ','))) {
597 mdefs->variant[i] = p;
602 if (p && (p = strchr(p, ',')))
610 FreeMultiDefs(XkbRF_MultiDefsPtr defs)
612 if (defs->options) _XkbFree(defs->options);
613 if (defs->layout[1]) _XkbFree(defs->layout[1]);
614 if (defs->variant[1]) _XkbFree(defs->variant[1]);
618 Apply(char *src, char **dst)
621 if (*src == '+' || *src == '!') {
622 *dst= _Concat(*dst, src);
625 *dst= _XkbDupString(src);
631 XkbRF_ApplyRule( XkbRF_RulePtr rule,
632 XkbComponentNamesPtr names)
634 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
636 Apply(rule->keycodes, &names->keycodes);
637 Apply(rule->symbols, &names->symbols);
638 Apply(rule->types, &names->types);
639 Apply(rule->compat, &names->compat);
640 Apply(rule->geometry, &names->geometry);
641 Apply(rule->keymap, &names->keymap);
645 CheckGroup( XkbRF_RulesPtr rules,
651 XkbRF_GroupPtr group;
653 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
654 if (! strcmp(group->name, group_name)) {
658 if (i == rules->num_groups)
660 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) {
661 if (! strcmp(p, name)) {
669 XkbRF_CheckApplyRule( XkbRF_RulePtr rule,
670 XkbRF_MultiDefsPtr mdefs,
671 XkbComponentNamesPtr names,
672 XkbRF_RulesPtr rules)
674 Bool pending = False;
676 if (rule->model != NULL) {
677 if(mdefs->model == NULL)
679 if (strcmp(rule->model, "*") == 0) {
682 if (rule->model[0] == '$') {
683 if (!CheckGroup(rules, rule->model, mdefs->model))
686 if (strcmp(rule->model, mdefs->model) != 0)
691 if (rule->option != NULL) {
692 if (mdefs->options == NULL)
694 if ((!MatchOneOf(rule->option,mdefs->options)))
698 if (rule->layout != NULL) {
699 if(mdefs->layout[rule->layout_num] == NULL ||
700 *mdefs->layout[rule->layout_num] == '\0')
702 if (strcmp(rule->layout, "*") == 0) {
705 if (rule->layout[0] == '$') {
706 if (!CheckGroup(rules, rule->layout,
707 mdefs->layout[rule->layout_num]))
710 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
715 if (rule->variant != NULL) {
716 if (mdefs->variant[rule->variant_num] == NULL ||
717 *mdefs->variant[rule->variant_num] == '\0')
719 if (strcmp(rule->variant, "*") == 0) {
722 if (rule->variant[0] == '$') {
723 if (!CheckGroup(rules, rule->variant,
724 mdefs->variant[rule->variant_num]))
727 if (strcmp(rule->variant,
728 mdefs->variant[rule->variant_num]) != 0)
734 rule->flags|= XkbRF_PendingMatch;
737 /* exact match, apply it now */
738 XkbRF_ApplyRule(rule,names);
743 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
748 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
749 rule->flags&= ~XkbRF_PendingMatch;
754 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names)
759 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
760 if ((rule->flags&XkbRF_PendingMatch)==0)
762 XkbRF_ApplyRule(rule,names);
767 XkbRF_CheckApplyRules( XkbRF_RulesPtr rules,
768 XkbRF_MultiDefsPtr mdefs,
769 XkbComponentNamesPtr names,
776 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) {
777 if ((rule->flags & flags) != flags)
779 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
780 if (skip && !(flags & XkbRF_Option)) {
781 for ( ;(i < rules->num_rules) && (rule->number == skip);
788 /***====================================================================***/
791 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
793 char *str, *outstr, *orig, *var;
797 str= index(name,'%');
804 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
813 str = get_index(var + 1, &ndx);
815 str = index(str,'%');
818 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
819 len+= strlen(mdefs->layout[ndx])+extra_len;
820 else if ((*var=='m')&&mdefs->model)
821 len+= strlen(mdefs->model)+extra_len;
822 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
823 len+= strlen(mdefs->variant[ndx])+extra_len;
824 if ((pfx=='(')&&(*str==')')) {
827 str= index(&str[0],'%');
829 name= (char *)_XkbAlloc(len+1);
838 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) {
848 str = get_index(var + 1, &ndx);
852 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
853 if (pfx) *outstr++= pfx;
854 strcpy(outstr,mdefs->layout[ndx]);
855 outstr+= strlen(mdefs->layout[ndx]);
856 if (sfx) *outstr++= sfx;
858 else if ((*var=='m')&&(mdefs->model)) {
859 if (pfx) *outstr++= pfx;
860 strcpy(outstr,mdefs->model);
861 outstr+= strlen(mdefs->model);
862 if (sfx) *outstr++= sfx;
864 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) {
865 if (pfx) *outstr++= pfx;
866 strcpy(outstr,mdefs->variant[ndx]);
867 outstr+= strlen(mdefs->variant[ndx]);
868 if (sfx) *outstr++= sfx;
870 if ((pfx=='(')&&(*str==')'))
883 /***====================================================================***/
886 XkbRF_GetComponents( XkbRF_RulesPtr rules,
887 XkbRF_VarDefsPtr defs,
888 XkbComponentNamesPtr names)
890 XkbRF_MultiDefsRec mdefs;
892 MakeMultiDefs(&mdefs, defs);
894 bzero((char *)names,sizeof(XkbComponentNamesRec));
895 XkbRF_ClearPartialMatches(rules);
896 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
897 XkbRF_ApplyPartialMatches(rules, names);
898 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
899 XkbRF_ApplyPartialMatches(rules, names);
900 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
901 XkbRF_ApplyPartialMatches(rules, names);
904 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs);
906 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs);
908 names->types= XkbRF_SubstituteVars(names->types, &mdefs);
910 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs);
912 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs);
914 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs);
916 FreeMultiDefs(&mdefs);
917 return (names->keycodes && names->symbols && names->types &&
918 names->compat && names->geometry ) || names->keymap;
922 XkbRF_AddRule(XkbRF_RulesPtr rules)
924 if (rules->sz_rules<1) {
927 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
929 else if (rules->num_rules>=rules->sz_rules) {
931 rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules,
935 rules->sz_rules= rules->num_rules= 0;
937 fprintf(stderr,"Allocation failure in XkbRF_AddRule\n");
941 bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec));
942 return &rules->rules[rules->num_rules++];
946 XkbRF_AddGroup(XkbRF_RulesPtr rules)
948 if (rules->sz_groups<1) {
949 rules->sz_groups= 16;
950 rules->num_groups= 0;
951 rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec);
953 else if (rules->num_groups >= rules->sz_groups) {
954 rules->sz_groups *= 2;
955 rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups,
958 if (!rules->groups) {
959 rules->sz_groups= rules->num_groups= 0;
963 bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec));
964 return &rules->groups[rules->num_groups++];
968 XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules)
972 XkbRF_RuleRec trule,*rule;
973 XkbRF_GroupRec tgroup,*group;
975 if (!(rules && file))
977 bzero((char *)&remap,sizeof(RemapSpec));
978 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
979 InitInputLine(&line);
980 while (GetInputLine(file,&line,True)) {
981 if (CheckLine(&line,&remap,&trule,&tgroup)) {
983 if ((group= XkbRF_AddGroup(rules))!=NULL) {
985 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec));
988 if ((rule= XkbRF_AddRule(rules))!=NULL) {
990 bzero((char *)&trule,sizeof(XkbRF_RuleRec));
996 FreeInputLine(&line);
1001 XkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules)
1007 if ((!base)||(!rules))
1010 if (strlen(base)+strlen(locale)+2 > PATH_MAX)
1012 sprintf(buf,"%s-%s", base, locale);
1015 if (strlen(base)+1 > PATH_MAX)
1020 file= fopen(buf, "r");
1021 if ((!file)&&(locale)) { /* fallback if locale was specified */
1023 file= fopen(buf, "r");
1027 ok= XkbRF_LoadRules(file,rules);
1032 /***====================================================================***/
1035 #define HEAD_MODEL 1
1036 #define HEAD_LAYOUT 2
1037 #define HEAD_VARIANT 3
1038 #define HEAD_OPTION 4
1039 #define HEAD_EXTRA 5
1042 XkbRF_AddVarDesc(XkbRF_DescribeVarsPtr vars)
1044 if (vars->sz_desc<1) {
1047 vars->desc= _XkbTypedCalloc(vars->sz_desc,XkbRF_VarDescRec);
1049 else if (vars->num_desc>=vars->sz_desc) {
1051 vars->desc= _XkbTypedRealloc(vars->desc,vars->sz_desc,XkbRF_VarDescRec);
1054 vars->sz_desc= vars->num_desc= 0;
1055 PR_DEBUG("Allocation failure in XkbRF_AddVarDesc\n");
1058 vars->desc[vars->num_desc].name= NULL;
1059 vars->desc[vars->num_desc].desc= NULL;
1060 return &vars->desc[vars->num_desc++];
1064 XkbRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars,XkbRF_VarDescPtr from)
1066 XkbRF_VarDescPtr nd;
1068 if ((nd=XkbRF_AddVarDesc(vars))!=NULL) {
1069 nd->name= _XkbDupString(from->name);
1070 nd->desc= _XkbDupString(from->desc);
1075 XkbRF_DescribeVarsPtr
1076 XkbRF_AddVarToDescribe(XkbRF_RulesPtr rules,char *name)
1078 if (rules->sz_extra<1) {
1079 rules->num_extra= 0;
1081 rules->extra_names= _XkbTypedCalloc(rules->sz_extra,char *);
1082 rules->extra= _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec);
1084 else if (rules->num_extra>=rules->sz_extra) {
1085 rules->sz_extra*= 2;
1086 rules->extra_names= _XkbTypedRealloc(rules->extra_names,rules->sz_extra,
1088 rules->extra=_XkbTypedRealloc(rules->extra, rules->sz_extra,
1089 XkbRF_DescribeVarsRec);
1091 if ((!rules->extra_names)||(!rules->extra)) {
1092 PR_DEBUG("allocation error in extra parts\n");
1093 rules->sz_extra= rules->num_extra= 0;
1094 rules->extra_names= NULL;
1098 rules->extra_names[rules->num_extra]= _XkbDupString(name);
1099 bzero(&rules->extra[rules->num_extra],sizeof(XkbRF_DescribeVarsRec));
1100 return &rules->extra[rules->num_extra++];
1104 XkbRF_LoadDescriptions(FILE *file,XkbRF_RulesPtr rules)
1107 XkbRF_VarDescRec tmp;
1109 int len,headingtype,extra_ndx = 0;
1111 bzero((char *)&tmp, sizeof(XkbRF_VarDescRec));
1112 headingtype = HEAD_NONE;
1113 InitInputLine(&line);
1114 for ( ; GetInputLine(file,&line,False); line.num_line= 0) {
1115 if (line.line[0]=='!') {
1116 tok = strtok(&(line.line[1]), " \t");
1117 if (strcmp(tok,"model") == 0)
1118 headingtype = HEAD_MODEL;
1119 else if (_XkbStrCaseCmp(tok,"layout") == 0)
1120 headingtype = HEAD_LAYOUT;
1121 else if (_XkbStrCaseCmp(tok,"variant") == 0)
1122 headingtype = HEAD_VARIANT;
1123 else if (_XkbStrCaseCmp(tok,"option") == 0)
1124 headingtype = HEAD_OPTION;
1127 headingtype = HEAD_EXTRA;
1129 for (i=0;(i<rules->num_extra)&&(extra_ndx<0);i++) {
1130 if (_XkbStrCaseCmp(tok,rules->extra_names[i]))
1134 XkbRF_DescribeVarsPtr var;
1135 PR_DEBUG1("Extra heading \"%s\" encountered\n",tok);
1136 var= XkbRF_AddVarToDescribe(rules,tok);
1138 extra_ndx= var-rules->extra;
1139 else headingtype= HEAD_NONE;
1145 if (headingtype == HEAD_NONE) {
1146 PR_DEBUG("Must have a heading before first line of data\n");
1147 PR_DEBUG("Illegal line of data ignored\n");
1151 len = strlen(line.line);
1152 if ((tmp.name= strtok(line.line, " \t")) == NULL) {
1153 PR_DEBUG("Huh? No token on line\n");
1154 PR_DEBUG("Illegal line of data ignored\n");
1157 if (strlen(tmp.name) == len) {
1158 PR_DEBUG("No description found\n");
1159 PR_DEBUG("Illegal line of data ignored\n");
1163 tok = line.line + strlen(tmp.name) + 1;
1164 while ((*tok!='\n')&&isspace(*tok))
1167 PR_DEBUG("No description found\n");
1168 PR_DEBUG("Illegal line of data ignored\n");
1172 switch (headingtype) {
1174 XkbRF_AddVarDescCopy(&rules->models,&tmp);
1177 XkbRF_AddVarDescCopy(&rules->layouts,&tmp);
1180 XkbRF_AddVarDescCopy(&rules->variants,&tmp);
1183 XkbRF_AddVarDescCopy(&rules->options,&tmp);
1186 XkbRF_AddVarDescCopy(&rules->extra[extra_ndx],&tmp);
1190 FreeInputLine(&line);
1191 if ((rules->models.num_desc==0) && (rules->layouts.num_desc==0) &&
1192 (rules->variants.num_desc==0) && (rules->options.num_desc==0) &&
1193 (rules->num_extra==0)) {
1200 XkbRF_LoadDescriptionsByName(char *base,char *locale,XkbRF_RulesPtr rules)
1206 if ((!base)||(!rules))
1209 if (strlen(base)+strlen(locale)+6 > PATH_MAX)
1211 sprintf(buf,"%s-%s.lst", base, locale);
1214 if (strlen(base)+5 > PATH_MAX)
1216 sprintf(buf,"%s.lst", base);
1219 file= fopen(buf, "r");
1220 if ((!file)&&(locale)) { /* fallback if locale was specified */
1221 sprintf(buf,"%s.lst", base);
1223 file= fopen(buf, "r");
1227 ok= XkbRF_LoadDescriptions(file,rules);
1232 /***====================================================================***/
1235 XkbRF_Load(char *base,char *locale,Bool wantDesc,Bool wantRules)
1237 XkbRF_RulesPtr rules;
1239 if ((!base)||((!wantDesc)&&(!wantRules)))
1241 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
1243 if (wantDesc&&(!XkbRF_LoadDescriptionsByName(base,locale,rules))) {
1244 XkbRF_Free(rules,True);
1247 if (wantRules&&(!XkbRF_LoadRulesByName(base,locale,rules))) {
1248 XkbRF_Free(rules,True);
1255 XkbRF_Create(int szRules,int szExtra)
1257 XkbRF_RulesPtr rules;
1259 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL)
1262 rules->sz_rules= szRules;
1263 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec);
1264 if (!rules->rules) {
1270 rules->sz_extra= szExtra;
1271 rules->extra= _XkbTypedCalloc(rules->sz_extra,XkbRF_DescribeVarsRec);
1272 if (!rules->extra) {
1274 _XkbFree(rules->rules);
1282 /***====================================================================***/
1285 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var)
1289 for (i=0;i<var->num_desc;i++) {
1290 if (var->desc[i].name)
1291 _XkbFree(var->desc[i].name);
1292 if (var->desc[i].desc)
1293 _XkbFree(var->desc[i].desc);
1294 var->desc[i].name= var->desc[i].desc= NULL;
1297 _XkbFree(var->desc);
1303 XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules)
1307 XkbRF_GroupPtr group;
1311 XkbRF_ClearVarDescriptions(&rules->models);
1312 XkbRF_ClearVarDescriptions(&rules->layouts);
1313 XkbRF_ClearVarDescriptions(&rules->variants);
1314 XkbRF_ClearVarDescriptions(&rules->options);
1316 for (i = 0; i < rules->num_extra; i++) {
1317 XkbRF_ClearVarDescriptions(&rules->extra[i]);
1319 _XkbFree(rules->extra);
1320 rules->num_extra= rules->sz_extra= 0;
1324 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) {
1325 if (rule->model) _XkbFree(rule->model);
1326 if (rule->layout) _XkbFree(rule->layout);
1327 if (rule->variant) _XkbFree(rule->variant);
1328 if (rule->option) _XkbFree(rule->option);
1329 if (rule->keycodes) _XkbFree(rule->keycodes);
1330 if (rule->symbols) _XkbFree(rule->symbols);
1331 if (rule->types) _XkbFree(rule->types);
1332 if (rule->compat) _XkbFree(rule->compat);
1333 if (rule->geometry) _XkbFree(rule->geometry);
1334 if (rule->keymap) _XkbFree(rule->keymap);
1335 bzero((char *)rule,sizeof(XkbRF_RuleRec));
1337 _XkbFree(rules->rules);
1338 rules->num_rules= rules->sz_rules= 0;
1342 if (rules->groups) {
1343 for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) {
1344 if (group->name) _XkbFree(group->name);
1345 if (group->words) _XkbFree(group->words);
1347 _XkbFree(rules->groups);
1348 rules->num_groups= 0;
1349 rules->groups= NULL;
1356 #ifndef XKB_IN_SERVER
1359 XkbRF_GetNamesProp(Display *dpy,char **rf_rtrn,XkbRF_VarDefsPtr vd_rtrn)
1361 Atom rules_atom,actual_type;
1363 unsigned long nitems,bytes_after;
1364 unsigned char *data;
1368 rules_atom= XInternAtom(dpy,_XKB_RF_NAMES_PROP_ATOM,True);
1369 if (rules_atom==None) /* property cannot exist */
1371 rtrn= XGetWindowProperty(dpy,DefaultRootWindow(dpy),rules_atom,
1372 0L,_XKB_RF_NAMES_PROP_MAXLEN,False,
1373 XA_STRING,&actual_type,
1374 &fmt,&nitems,&bytes_after,
1375 (unsigned char **)&data);
1380 (void)bzero((char *)vd_rtrn,sizeof(XkbRF_VarDefsRec));
1381 if ((bytes_after>0)||(actual_type!=XA_STRING)||(fmt!=8)) {
1382 if (data) XFree(data);
1383 return (fmt==0?True:False);
1388 if (out && (*out) && rf_rtrn)
1389 *rf_rtrn= _XkbDupString(out);
1394 vd_rtrn->model= _XkbDupString(out);
1400 vd_rtrn->layout= _XkbDupString(out);
1406 vd_rtrn->variant= _XkbDupString(out);
1412 vd_rtrn->options= _XkbDupString(out);
1421 XkbRF_SetNamesProp(Display *dpy,char *rules_file,XkbRF_VarDefsPtr var_defs)
1427 len= (rules_file?strlen(rules_file):0);
1428 len+= (var_defs->model?strlen(var_defs->model):0);
1429 len+= (var_defs->layout?strlen(var_defs->layout):0);
1430 len+= (var_defs->variant?strlen(var_defs->variant):0);
1431 len+= (var_defs->options?strlen(var_defs->options):0);
1435 len+= 5; /* trailing NULs */
1437 name= XInternAtom(dpy,_XKB_RF_NAMES_PROP_ATOM,False);
1438 if (name==None) { /* should never happen */
1439 _XkbLibError(_XkbErrXReqFailure,"XkbRF_SetNamesProp",X_InternAtom);
1442 pval= (char *)_XkbAlloc(len);
1444 _XkbLibError(_XkbErrBadAlloc,"XkbRF_SetNamesProp",len);
1449 strcpy(&pval[out],rules_file);
1450 out+= strlen(rules_file);
1453 if (var_defs->model) {
1454 strcpy(&pval[out],var_defs->model);
1455 out+= strlen(var_defs->model);
1458 if (var_defs->layout) {
1459 strcpy(&pval[out],var_defs->layout);
1460 out+= strlen(var_defs->layout);
1463 if (var_defs->variant) {
1464 strcpy(&pval[out],var_defs->variant);
1465 out+= strlen(var_defs->variant);
1468 if (var_defs->options) {
1469 strcpy(&pval[out],var_defs->options);
1470 out+= strlen(var_defs->options);
1474 _XkbLibError(_XkbErrBadLength,"XkbRF_SetNamesProp",out);
1479 XChangeProperty(dpy,DefaultRootWindow(dpy),name,XA_STRING,8,PropModeReplace,
1480 (unsigned char *)pval,len);