1706f2543Smrg/************************************************************ 2706f2543Smrg Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc. 3706f2543Smrg 4706f2543Smrg Permission to use, copy, modify, and distribute this 5706f2543Smrg software and its documentation for any purpose and without 6706f2543Smrg fee is hereby granted, provided that the above copyright 7706f2543Smrg notice appear in all copies and that both that copyright 8706f2543Smrg notice and this permission notice appear in supporting 9706f2543Smrg documentation, and that the name of Silicon Graphics not be 10706f2543Smrg used in advertising or publicity pertaining to distribution 11706f2543Smrg of the software without specific prior written permission. 12706f2543Smrg Silicon Graphics makes no representation about the suitability 13706f2543Smrg of this software for any purpose. It is provided "as is" 14706f2543Smrg without any express or implied warranty. 15706f2543Smrg 16706f2543Smrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 17706f2543Smrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 18706f2543Smrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 19706f2543Smrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 20706f2543Smrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21706f2543Smrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 22706f2543Smrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 23706f2543Smrg THE USE OR PERFORMANCE OF THIS SOFTWARE. 24706f2543Smrg 25706f2543Smrg ********************************************************/ 26706f2543Smrg 27706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 28706f2543Smrg#include <dix-config.h> 29706f2543Smrg#endif 30706f2543Smrg 31706f2543Smrg#include <stdio.h> 32706f2543Smrg#include <ctype.h> 33706f2543Smrg#include <stdlib.h> 34706f2543Smrg 35706f2543Smrg#define X_INCLUDE_STRING_H 36706f2543Smrg#define XOS_USE_NO_LOCKING 37706f2543Smrg#include <X11/Xos_r.h> 38706f2543Smrg 39706f2543Smrg#include <X11/Xproto.h> 40706f2543Smrg#include <X11/X.h> 41706f2543Smrg#include <X11/Xos.h> 42706f2543Smrg#include <X11/Xfuncs.h> 43706f2543Smrg#include <X11/Xatom.h> 44706f2543Smrg#include <X11/keysym.h> 45706f2543Smrg#include "misc.h" 46706f2543Smrg#include "inputstr.h" 47706f2543Smrg#include "dix.h" 48706f2543Smrg#include "os.h" 49706f2543Smrg#include "xkbstr.h" 50706f2543Smrg#define XKBSRV_NEED_FILE_FUNCS 51706f2543Smrg#include <xkbsrv.h> 52706f2543Smrg 53706f2543Smrg/***====================================================================***/ 54706f2543Smrg 55706f2543Smrg 56706f2543Smrg 57706f2543Smrg#define DFLT_LINE_SIZE 128 58706f2543Smrg 59706f2543Smrgtypedef struct { 60706f2543Smrg int line_num; 61706f2543Smrg int sz_line; 62706f2543Smrg int num_line; 63706f2543Smrg char buf[DFLT_LINE_SIZE]; 64706f2543Smrg char * line; 65706f2543Smrg} InputLine; 66706f2543Smrg 67706f2543Smrgstatic void 68706f2543SmrgInitInputLine(InputLine *line) 69706f2543Smrg{ 70706f2543Smrg line->line_num= 1; 71706f2543Smrg line->num_line= 0; 72706f2543Smrg line->sz_line= DFLT_LINE_SIZE; 73706f2543Smrg line->line= line->buf; 74706f2543Smrg return; 75706f2543Smrg} 76706f2543Smrg 77706f2543Smrgstatic void 78706f2543SmrgFreeInputLine(InputLine *line) 79706f2543Smrg{ 80706f2543Smrg if (line->line!=line->buf) 81706f2543Smrg free(line->line); 82706f2543Smrg line->line_num= 1; 83706f2543Smrg line->num_line= 0; 84706f2543Smrg line->sz_line= DFLT_LINE_SIZE; 85706f2543Smrg line->line= line->buf; 86706f2543Smrg return; 87706f2543Smrg} 88706f2543Smrg 89706f2543Smrgstatic int 90706f2543SmrgInputLineAddChar(InputLine *line,int ch) 91706f2543Smrg{ 92706f2543Smrg if (line->num_line>=line->sz_line) { 93706f2543Smrg if (line->line==line->buf) { 94706f2543Smrg line->line= malloc(line->sz_line*2); 95706f2543Smrg memcpy(line->line,line->buf,line->sz_line); 96706f2543Smrg } 97706f2543Smrg else { 98706f2543Smrg line->line= realloc((char *)line->line,line->sz_line*2); 99706f2543Smrg } 100706f2543Smrg line->sz_line*= 2; 101706f2543Smrg } 102706f2543Smrg line->line[line->num_line++]= ch; 103706f2543Smrg return ch; 104706f2543Smrg} 105706f2543Smrg 106706f2543Smrg#define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\ 107706f2543Smrg (int)((l)->line[(l)->num_line++]= (c)):\ 108706f2543Smrg InputLineAddChar(l,c)) 109706f2543Smrg 110706f2543Smrgstatic Bool 111706f2543SmrgGetInputLine(FILE *file,InputLine *line,Bool checkbang) 112706f2543Smrg{ 113706f2543Smrgint ch; 114706f2543SmrgBool endOfFile,spacePending,slashPending,inComment; 115706f2543Smrg 116706f2543Smrg endOfFile= FALSE; 117706f2543Smrg while ((!endOfFile)&&(line->num_line==0)) { 118706f2543Smrg spacePending= slashPending= inComment= FALSE; 119706f2543Smrg while (((ch=getc(file))!='\n')&&(ch!=EOF)) { 120706f2543Smrg if (ch=='\\') { 121706f2543Smrg if ((ch=getc(file))==EOF) 122706f2543Smrg break; 123706f2543Smrg if (ch=='\n') { 124706f2543Smrg inComment= FALSE; 125706f2543Smrg ch= ' '; 126706f2543Smrg line->line_num++; 127706f2543Smrg } 128706f2543Smrg } 129706f2543Smrg if (inComment) 130706f2543Smrg continue; 131706f2543Smrg if (ch=='/') { 132706f2543Smrg if (slashPending) { 133706f2543Smrg inComment= TRUE; 134706f2543Smrg slashPending= FALSE; 135706f2543Smrg } 136706f2543Smrg else { 137706f2543Smrg slashPending= TRUE; 138706f2543Smrg } 139706f2543Smrg continue; 140706f2543Smrg } 141706f2543Smrg else if (slashPending) { 142706f2543Smrg if (spacePending) { 143706f2543Smrg ADD_CHAR(line,' '); 144706f2543Smrg spacePending= FALSE; 145706f2543Smrg } 146706f2543Smrg ADD_CHAR(line,'/'); 147706f2543Smrg slashPending= FALSE; 148706f2543Smrg } 149706f2543Smrg if (isspace(ch)) { 150706f2543Smrg while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) { 151706f2543Smrg ch= getc(file); 152706f2543Smrg } 153706f2543Smrg if (ch==EOF) 154706f2543Smrg break; 155706f2543Smrg if ((ch!='\n')&&(line->num_line>0)) 156706f2543Smrg spacePending= TRUE; 157706f2543Smrg ungetc(ch,file); 158706f2543Smrg } 159706f2543Smrg else { 160706f2543Smrg if (spacePending) { 161706f2543Smrg ADD_CHAR(line,' '); 162706f2543Smrg spacePending= FALSE; 163706f2543Smrg } 164706f2543Smrg if (checkbang && ch=='!') { 165706f2543Smrg if (line->num_line!=0) { 166706f2543Smrg DebugF("The '!' legal only at start of line\n"); 167706f2543Smrg DebugF("Line containing '!' ignored\n"); 168706f2543Smrg line->num_line= 0; 169706f2543Smrg inComment= 0; 170706f2543Smrg break; 171706f2543Smrg } 172706f2543Smrg 173706f2543Smrg } 174706f2543Smrg ADD_CHAR(line,ch); 175706f2543Smrg } 176706f2543Smrg } 177706f2543Smrg if (ch==EOF) 178706f2543Smrg endOfFile= TRUE; 179706f2543Smrg/* else line->num_line++;*/ 180706f2543Smrg } 181706f2543Smrg if ((line->num_line==0)&&(endOfFile)) 182706f2543Smrg return FALSE; 183706f2543Smrg ADD_CHAR(line,'\0'); 184706f2543Smrg return TRUE; 185706f2543Smrg} 186706f2543Smrg 187706f2543Smrg/***====================================================================***/ 188706f2543Smrg 189706f2543Smrg#define MODEL 0 190706f2543Smrg#define LAYOUT 1 191706f2543Smrg#define VARIANT 2 192706f2543Smrg#define OPTION 3 193706f2543Smrg#define KEYCODES 4 194706f2543Smrg#define SYMBOLS 5 195706f2543Smrg#define TYPES 6 196706f2543Smrg#define COMPAT 7 197706f2543Smrg#define GEOMETRY 8 198706f2543Smrg#define MAX_WORDS 9 199706f2543Smrg 200706f2543Smrg#define PART_MASK 0x000F 201706f2543Smrg#define COMPONENT_MASK 0x03F0 202706f2543Smrg 203706f2543Smrgstatic char * cname[MAX_WORDS] = { 204706f2543Smrg "model", "layout", "variant", "option", 205706f2543Smrg "keycodes", "symbols", "types", "compat", "geometry" 206706f2543Smrg}; 207706f2543Smrg 208706f2543Smrgtypedef struct _RemapSpec { 209706f2543Smrg int number; 210706f2543Smrg int num_remap; 211706f2543Smrg struct { 212706f2543Smrg int word; 213706f2543Smrg int index; 214706f2543Smrg } remap[MAX_WORDS]; 215706f2543Smrg} RemapSpec; 216706f2543Smrg 217706f2543Smrgtypedef struct _FileSpec { 218706f2543Smrg char * name[MAX_WORDS]; 219706f2543Smrg struct _FileSpec * pending; 220706f2543Smrg} FileSpec; 221706f2543Smrg 222706f2543Smrgtypedef struct { 223706f2543Smrg char * model; 224706f2543Smrg char * layout[XkbNumKbdGroups+1]; 225706f2543Smrg char * variant[XkbNumKbdGroups+1]; 226706f2543Smrg char * options; 227706f2543Smrg} XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr; 228706f2543Smrg 229706f2543Smrg#define NDX_BUFF_SIZE 4 230706f2543Smrg 231706f2543Smrg/***====================================================================***/ 232706f2543Smrg 233706f2543Smrgstatic char* 234706f2543Smrgget_index(char *str, int *ndx) 235706f2543Smrg{ 236706f2543Smrg char ndx_buf[NDX_BUFF_SIZE]; 237706f2543Smrg char *end; 238706f2543Smrg 239706f2543Smrg if (*str != '[') { 240706f2543Smrg *ndx = 0; 241706f2543Smrg return str; 242706f2543Smrg } 243706f2543Smrg str++; 244706f2543Smrg end = strchr(str, ']'); 245706f2543Smrg if (end == NULL) { 246706f2543Smrg *ndx = -1; 247706f2543Smrg return str - 1; 248706f2543Smrg } 249706f2543Smrg if ( (end - str) >= NDX_BUFF_SIZE) { 250706f2543Smrg *ndx = -1; 251706f2543Smrg return end + 1; 252706f2543Smrg } 253706f2543Smrg strncpy(ndx_buf, str, end - str); 254706f2543Smrg ndx_buf[end - str] = '\0'; 255706f2543Smrg *ndx = atoi(ndx_buf); 256706f2543Smrg return end + 1; 257706f2543Smrg} 258706f2543Smrg 259706f2543Smrgstatic void 260706f2543SmrgSetUpRemap(InputLine *line,RemapSpec *remap) 261706f2543Smrg{ 262706f2543Smrgchar * tok,*str; 263706f2543Smrgunsigned present, l_ndx_present, v_ndx_present; 264706f2543Smrgregister int i; 265706f2543Smrgint len, ndx; 266706f2543Smrg_Xstrtokparams strtok_buf; 267706f2543SmrgBool found; 268706f2543Smrg 269706f2543Smrg 270706f2543Smrg l_ndx_present = v_ndx_present = present= 0; 271706f2543Smrg str= &line->line[1]; 272706f2543Smrg len = remap->number; 273706f2543Smrg memset((char *)remap, 0, sizeof(RemapSpec)); 274706f2543Smrg remap->number = len; 275706f2543Smrg while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) { 276706f2543Smrg found= FALSE; 277706f2543Smrg str= NULL; 278706f2543Smrg if (strcmp(tok,"=")==0) 279706f2543Smrg continue; 280706f2543Smrg for (i=0;i<MAX_WORDS;i++) { 281706f2543Smrg len = strlen(cname[i]); 282706f2543Smrg if (strncmp(cname[i],tok,len)==0) { 283706f2543Smrg if(strlen(tok) > len) { 284706f2543Smrg char *end = get_index(tok+len, &ndx); 285706f2543Smrg if ((i != LAYOUT && i != VARIANT) || 286706f2543Smrg *end != '\0' || ndx == -1) 287706f2543Smrg break; 288706f2543Smrg if (ndx < 1 || ndx > XkbNumKbdGroups) { 289706f2543Smrg DebugF("Illegal %s index: %d\n", cname[i], ndx); 290706f2543Smrg DebugF("Index must be in range 1..%d\n", 291706f2543Smrg XkbNumKbdGroups); 292706f2543Smrg break; 293706f2543Smrg } 294706f2543Smrg } else { 295706f2543Smrg ndx = 0; 296706f2543Smrg } 297706f2543Smrg found= TRUE; 298706f2543Smrg if (present&(1<<i)) { 299706f2543Smrg if ((i == LAYOUT && l_ndx_present&(1<<ndx)) || 300706f2543Smrg (i == VARIANT && v_ndx_present&(1<<ndx)) ) { 301706f2543Smrg DebugF("Component \"%s\" listed twice\n",tok); 302706f2543Smrg DebugF("Second definition ignored\n"); 303706f2543Smrg break; 304706f2543Smrg } 305706f2543Smrg } 306706f2543Smrg present |= (1<<i); 307706f2543Smrg if (i == LAYOUT) 308706f2543Smrg l_ndx_present |= 1 << ndx; 309706f2543Smrg if (i == VARIANT) 310706f2543Smrg v_ndx_present |= 1 << ndx; 311706f2543Smrg remap->remap[remap->num_remap].word= i; 312706f2543Smrg remap->remap[remap->num_remap++].index= ndx; 313706f2543Smrg break; 314706f2543Smrg } 315706f2543Smrg } 316706f2543Smrg if (!found) { 317706f2543Smrg fprintf(stderr,"Unknown component \"%s\" ignored\n",tok); 318706f2543Smrg } 319706f2543Smrg } 320706f2543Smrg if ((present&PART_MASK)==0) { 321706f2543Smrg unsigned mask= PART_MASK; 322706f2543Smrg ErrorF("Mapping needs at least one of "); 323706f2543Smrg for (i=0; (i<MAX_WORDS); i++) { 324706f2543Smrg if ((1L<<i)&mask) { 325706f2543Smrg mask&= ~(1L<<i); 326706f2543Smrg if (mask) DebugF("\"%s,\" ",cname[i]); 327706f2543Smrg else DebugF("or \"%s\"\n",cname[i]); 328706f2543Smrg } 329706f2543Smrg } 330706f2543Smrg DebugF("Illegal mapping ignored\n"); 331706f2543Smrg remap->num_remap= 0; 332706f2543Smrg return; 333706f2543Smrg } 334706f2543Smrg if ((present&COMPONENT_MASK)==0) { 335706f2543Smrg DebugF("Mapping needs at least one component\n"); 336706f2543Smrg DebugF("Illegal mapping ignored\n"); 337706f2543Smrg remap->num_remap= 0; 338706f2543Smrg return; 339706f2543Smrg } 340706f2543Smrg remap->number++; 341706f2543Smrg return; 342706f2543Smrg} 343706f2543Smrg 344706f2543Smrgstatic Bool 345706f2543SmrgMatchOneOf(char *wanted,char *vals_defined) 346706f2543Smrg{ 347706f2543Smrgchar *str,*next; 348706f2543Smrgint want_len= strlen(wanted); 349706f2543Smrg 350706f2543Smrg for (str=vals_defined,next=NULL;str!=NULL;str=next) { 351706f2543Smrg int len; 352706f2543Smrg next= strchr(str,','); 353706f2543Smrg if (next) { 354706f2543Smrg len= next-str; 355706f2543Smrg next++; 356706f2543Smrg } 357706f2543Smrg else { 358706f2543Smrg len= strlen(str); 359706f2543Smrg } 360706f2543Smrg if ((len==want_len)&&(strncmp(wanted,str,len)==0)) 361706f2543Smrg return TRUE; 362706f2543Smrg } 363706f2543Smrg return FALSE; 364706f2543Smrg} 365706f2543Smrg 366706f2543Smrg/***====================================================================***/ 367706f2543Smrg 368706f2543Smrgstatic Bool 369706f2543SmrgCheckLine( InputLine * line, 370706f2543Smrg RemapSpec * remap, 371706f2543Smrg XkbRF_RulePtr rule, 372706f2543Smrg XkbRF_GroupPtr group) 373706f2543Smrg{ 374706f2543Smrgchar * str,*tok; 375706f2543Smrgregister int nread, i; 376706f2543SmrgFileSpec tmp; 377706f2543Smrg_Xstrtokparams strtok_buf; 378706f2543SmrgBool append = FALSE; 379706f2543Smrg 380706f2543Smrg if (line->line[0]=='!') { 381706f2543Smrg if (line->line[1] == '$' || 382706f2543Smrg (line->line[1] == ' ' && line->line[2] == '$')) { 383706f2543Smrg char *gname = strchr(line->line, '$'); 384706f2543Smrg char *words = strchr(gname, ' '); 385706f2543Smrg if(!words) 386706f2543Smrg return FALSE; 387706f2543Smrg *words++ = '\0'; 388706f2543Smrg for (; *words; words++) { 389706f2543Smrg if (*words != '=' && *words != ' ') 390706f2543Smrg break; 391706f2543Smrg } 392706f2543Smrg if (*words == '\0') 393706f2543Smrg return FALSE; 394706f2543Smrg group->name = _XkbDupString(gname); 395706f2543Smrg group->words = _XkbDupString(words); 396706f2543Smrg for (i = 1, words = group->words; *words; words++) { 397706f2543Smrg if ( *words == ' ') { 398706f2543Smrg *words++ = '\0'; 399706f2543Smrg i++; 400706f2543Smrg } 401706f2543Smrg } 402706f2543Smrg group->number = i; 403706f2543Smrg return TRUE; 404706f2543Smrg } else { 405706f2543Smrg SetUpRemap(line,remap); 406706f2543Smrg return FALSE; 407706f2543Smrg } 408706f2543Smrg } 409706f2543Smrg 410706f2543Smrg if (remap->num_remap==0) { 411706f2543Smrg DebugF("Must have a mapping before first line of data\n"); 412706f2543Smrg DebugF("Illegal line of data ignored\n"); 413706f2543Smrg return FALSE; 414706f2543Smrg } 415706f2543Smrg memset((char *)&tmp, 0, sizeof(FileSpec)); 416706f2543Smrg str= line->line; 417706f2543Smrg for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) { 418706f2543Smrg str= NULL; 419706f2543Smrg if (strcmp(tok,"=")==0) { 420706f2543Smrg nread--; 421706f2543Smrg continue; 422706f2543Smrg } 423706f2543Smrg if (nread>remap->num_remap) { 424706f2543Smrg DebugF("Too many words on a line\n"); 425706f2543Smrg DebugF("Extra word \"%s\" ignored\n",tok); 426706f2543Smrg continue; 427706f2543Smrg } 428706f2543Smrg tmp.name[remap->remap[nread].word]= tok; 429706f2543Smrg if (*tok == '+' || *tok == '|') 430706f2543Smrg append = TRUE; 431706f2543Smrg } 432706f2543Smrg if (nread<remap->num_remap) { 433706f2543Smrg DebugF("Too few words on a line: %s\n", line->line); 434706f2543Smrg DebugF("line ignored\n"); 435706f2543Smrg return FALSE; 436706f2543Smrg } 437706f2543Smrg 438706f2543Smrg rule->flags= 0; 439706f2543Smrg rule->number = remap->number; 440706f2543Smrg if (tmp.name[OPTION]) 441706f2543Smrg rule->flags|= XkbRF_Option; 442706f2543Smrg else if (append) 443706f2543Smrg rule->flags|= XkbRF_Append; 444706f2543Smrg else 445706f2543Smrg rule->flags|= XkbRF_Normal; 446706f2543Smrg rule->model= _XkbDupString(tmp.name[MODEL]); 447706f2543Smrg rule->layout= _XkbDupString(tmp.name[LAYOUT]); 448706f2543Smrg rule->variant= _XkbDupString(tmp.name[VARIANT]); 449706f2543Smrg rule->option= _XkbDupString(tmp.name[OPTION]); 450706f2543Smrg 451706f2543Smrg rule->keycodes= _XkbDupString(tmp.name[KEYCODES]); 452706f2543Smrg rule->symbols= _XkbDupString(tmp.name[SYMBOLS]); 453706f2543Smrg rule->types= _XkbDupString(tmp.name[TYPES]); 454706f2543Smrg rule->compat= _XkbDupString(tmp.name[COMPAT]); 455706f2543Smrg rule->geometry= _XkbDupString(tmp.name[GEOMETRY]); 456706f2543Smrg 457706f2543Smrg rule->layout_num = rule->variant_num = 0; 458706f2543Smrg for (i = 0; i < nread; i++) { 459706f2543Smrg if (remap->remap[i].index) { 460706f2543Smrg if (remap->remap[i].word == LAYOUT) 461706f2543Smrg rule->layout_num = remap->remap[i].index; 462706f2543Smrg if (remap->remap[i].word == VARIANT) 463706f2543Smrg rule->variant_num = remap->remap[i].index; 464706f2543Smrg } 465706f2543Smrg } 466706f2543Smrg return TRUE; 467706f2543Smrg} 468706f2543Smrg 469706f2543Smrgstatic char * 470706f2543Smrg_Concat(char *str1,char *str2) 471706f2543Smrg{ 472706f2543Smrgint len; 473706f2543Smrg 474706f2543Smrg if ((!str1)||(!str2)) 475706f2543Smrg return str1; 476706f2543Smrg len= strlen(str1)+strlen(str2)+1; 477706f2543Smrg str1= realloc(str1,len * sizeof(char)); 478706f2543Smrg if (str1) 479706f2543Smrg strcat(str1,str2); 480706f2543Smrg return str1; 481706f2543Smrg} 482706f2543Smrg 483706f2543Smrgstatic void 484706f2543Smrgsqueeze_spaces(char *p1) 485706f2543Smrg{ 486706f2543Smrg char *p2; 487706f2543Smrg for (p2 = p1; *p2; p2++) { 488706f2543Smrg *p1 = *p2; 489706f2543Smrg if (*p1 != ' ') p1++; 490706f2543Smrg } 491706f2543Smrg *p1 = '\0'; 492706f2543Smrg} 493706f2543Smrg 494706f2543Smrgstatic Bool 495706f2543SmrgMakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs) 496706f2543Smrg{ 497706f2543Smrg 498706f2543Smrg memset((char *)mdefs, 0, sizeof(XkbRF_MultiDefsRec)); 499706f2543Smrg mdefs->model = defs->model; 500706f2543Smrg mdefs->options = _XkbDupString(defs->options); 501706f2543Smrg if (mdefs->options) squeeze_spaces(mdefs->options); 502706f2543Smrg 503706f2543Smrg if (defs->layout) { 504706f2543Smrg if (!strchr(defs->layout, ',')) { 505706f2543Smrg mdefs->layout[0] = defs->layout; 506706f2543Smrg } else { 507706f2543Smrg char *p; 508706f2543Smrg int i; 509706f2543Smrg mdefs->layout[1] = _XkbDupString(defs->layout); 510706f2543Smrg if (mdefs->layout[1] == NULL) 511706f2543Smrg return FALSE; 512706f2543Smrg squeeze_spaces(mdefs->layout[1]); 513706f2543Smrg p = mdefs->layout[1]; 514706f2543Smrg for (i = 2; i <= XkbNumKbdGroups; i++) { 515706f2543Smrg if ((p = strchr(p, ','))) { 516706f2543Smrg *p++ = '\0'; 517706f2543Smrg mdefs->layout[i] = p; 518706f2543Smrg } else { 519706f2543Smrg break; 520706f2543Smrg } 521706f2543Smrg } 522706f2543Smrg if (p && (p = strchr(p, ','))) 523706f2543Smrg *p = '\0'; 524706f2543Smrg } 525706f2543Smrg } 526706f2543Smrg 527706f2543Smrg if (defs->variant) { 528706f2543Smrg if (!strchr(defs->variant, ',')) { 529706f2543Smrg mdefs->variant[0] = defs->variant; 530706f2543Smrg } else { 531706f2543Smrg char *p; 532706f2543Smrg int i; 533706f2543Smrg mdefs->variant[1] = _XkbDupString(defs->variant); 534706f2543Smrg if (mdefs->variant[1] == NULL) 535706f2543Smrg return FALSE; 536706f2543Smrg squeeze_spaces(mdefs->variant[1]); 537706f2543Smrg p = mdefs->variant[1]; 538706f2543Smrg for (i = 2; i <= XkbNumKbdGroups; i++) { 539706f2543Smrg if ((p = strchr(p, ','))) { 540706f2543Smrg *p++ = '\0'; 541706f2543Smrg mdefs->variant[i] = p; 542706f2543Smrg } else { 543706f2543Smrg break; 544706f2543Smrg } 545706f2543Smrg } 546706f2543Smrg if (p && (p = strchr(p, ','))) 547706f2543Smrg *p = '\0'; 548706f2543Smrg } 549706f2543Smrg } 550706f2543Smrg return TRUE; 551706f2543Smrg} 552706f2543Smrg 553706f2543Smrgstatic void 554706f2543SmrgFreeMultiDefs(XkbRF_MultiDefsPtr defs) 555706f2543Smrg{ 556706f2543Smrg free(defs->options); 557706f2543Smrg free(defs->layout[1]); 558706f2543Smrg free(defs->variant[1]); 559706f2543Smrg} 560706f2543Smrg 561706f2543Smrgstatic void 562706f2543SmrgApply(char *src, char **dst) 563706f2543Smrg{ 564706f2543Smrg if (src) { 565706f2543Smrg if (*src == '+' || *src == '!') { 566706f2543Smrg *dst= _Concat(*dst, src); 567706f2543Smrg } else { 568706f2543Smrg if (*dst == NULL) 569706f2543Smrg *dst= _XkbDupString(src); 570706f2543Smrg } 571706f2543Smrg } 572706f2543Smrg} 573706f2543Smrg 574706f2543Smrgstatic void 575706f2543SmrgXkbRF_ApplyRule( XkbRF_RulePtr rule, 576706f2543Smrg XkbComponentNamesPtr names) 577706f2543Smrg{ 578706f2543Smrg rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */ 579706f2543Smrg 580706f2543Smrg Apply(rule->keycodes, &names->keycodes); 581706f2543Smrg Apply(rule->symbols, &names->symbols); 582706f2543Smrg Apply(rule->types, &names->types); 583706f2543Smrg Apply(rule->compat, &names->compat); 584706f2543Smrg Apply(rule->geometry, &names->geometry); 585706f2543Smrg} 586706f2543Smrg 587706f2543Smrgstatic Bool 588706f2543SmrgCheckGroup( XkbRF_RulesPtr rules, 589706f2543Smrg char * group_name, 590706f2543Smrg char * name) 591706f2543Smrg{ 592706f2543Smrg int i; 593706f2543Smrg char *p; 594706f2543Smrg XkbRF_GroupPtr group; 595706f2543Smrg 596706f2543Smrg for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) { 597706f2543Smrg if (! strcmp(group->name, group_name)) { 598706f2543Smrg break; 599706f2543Smrg } 600706f2543Smrg } 601706f2543Smrg if (i == rules->num_groups) 602706f2543Smrg return FALSE; 603706f2543Smrg for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) { 604706f2543Smrg if (! strcmp(p, name)) { 605706f2543Smrg return TRUE; 606706f2543Smrg } 607706f2543Smrg } 608706f2543Smrg return FALSE; 609706f2543Smrg} 610706f2543Smrg 611706f2543Smrgstatic int 612706f2543SmrgXkbRF_CheckApplyRule( XkbRF_RulePtr rule, 613706f2543Smrg XkbRF_MultiDefsPtr mdefs, 614706f2543Smrg XkbComponentNamesPtr names, 615706f2543Smrg XkbRF_RulesPtr rules) 616706f2543Smrg{ 617706f2543Smrg Bool pending = FALSE; 618706f2543Smrg 619706f2543Smrg if (rule->model != NULL) { 620706f2543Smrg if(mdefs->model == NULL) 621706f2543Smrg return 0; 622706f2543Smrg if (strcmp(rule->model, "*") == 0) { 623706f2543Smrg pending = TRUE; 624706f2543Smrg } else { 625706f2543Smrg if (rule->model[0] == '$') { 626706f2543Smrg if (!CheckGroup(rules, rule->model, mdefs->model)) 627706f2543Smrg return 0; 628706f2543Smrg } else { 629706f2543Smrg if (strcmp(rule->model, mdefs->model) != 0) 630706f2543Smrg return 0; 631706f2543Smrg } 632706f2543Smrg } 633706f2543Smrg } 634706f2543Smrg if (rule->option != NULL) { 635706f2543Smrg if (mdefs->options == NULL) 636706f2543Smrg return 0; 637706f2543Smrg if ((!MatchOneOf(rule->option,mdefs->options))) 638706f2543Smrg return 0; 639706f2543Smrg } 640706f2543Smrg 641706f2543Smrg if (rule->layout != NULL) { 642706f2543Smrg if(mdefs->layout[rule->layout_num] == NULL || 643706f2543Smrg *mdefs->layout[rule->layout_num] == '\0') 644706f2543Smrg return 0; 645706f2543Smrg if (strcmp(rule->layout, "*") == 0) { 646706f2543Smrg pending = TRUE; 647706f2543Smrg } else { 648706f2543Smrg if (rule->layout[0] == '$') { 649706f2543Smrg if (!CheckGroup(rules, rule->layout, 650706f2543Smrg mdefs->layout[rule->layout_num])) 651706f2543Smrg return 0; 652706f2543Smrg } else { 653706f2543Smrg if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0) 654706f2543Smrg return 0; 655706f2543Smrg } 656706f2543Smrg } 657706f2543Smrg } 658706f2543Smrg if (rule->variant != NULL) { 659706f2543Smrg if (mdefs->variant[rule->variant_num] == NULL || 660706f2543Smrg *mdefs->variant[rule->variant_num] == '\0') 661706f2543Smrg return 0; 662706f2543Smrg if (strcmp(rule->variant, "*") == 0) { 663706f2543Smrg pending = TRUE; 664706f2543Smrg } else { 665706f2543Smrg if (rule->variant[0] == '$') { 666706f2543Smrg if (!CheckGroup(rules, rule->variant, 667706f2543Smrg mdefs->variant[rule->variant_num])) 668706f2543Smrg return 0; 669706f2543Smrg } else { 670706f2543Smrg if (strcmp(rule->variant, 671706f2543Smrg mdefs->variant[rule->variant_num]) != 0) 672706f2543Smrg return 0; 673706f2543Smrg } 674706f2543Smrg } 675706f2543Smrg } 676706f2543Smrg if (pending) { 677706f2543Smrg rule->flags|= XkbRF_PendingMatch; 678706f2543Smrg return rule->number; 679706f2543Smrg } 680706f2543Smrg /* exact match, apply it now */ 681706f2543Smrg XkbRF_ApplyRule(rule,names); 682706f2543Smrg return rule->number; 683706f2543Smrg} 684706f2543Smrg 685706f2543Smrgstatic void 686706f2543SmrgXkbRF_ClearPartialMatches(XkbRF_RulesPtr rules) 687706f2543Smrg{ 688706f2543Smrgregister int i; 689706f2543SmrgXkbRF_RulePtr rule; 690706f2543Smrg 691706f2543Smrg for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { 692706f2543Smrg rule->flags&= ~XkbRF_PendingMatch; 693706f2543Smrg } 694706f2543Smrg} 695706f2543Smrg 696706f2543Smrgstatic void 697706f2543SmrgXkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names) 698706f2543Smrg{ 699706f2543Smrgint i; 700706f2543SmrgXkbRF_RulePtr rule; 701706f2543Smrg 702706f2543Smrg for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) { 703706f2543Smrg if ((rule->flags&XkbRF_PendingMatch)==0) 704706f2543Smrg continue; 705706f2543Smrg XkbRF_ApplyRule(rule,names); 706706f2543Smrg } 707706f2543Smrg} 708706f2543Smrg 709706f2543Smrgstatic void 710706f2543SmrgXkbRF_CheckApplyRules( XkbRF_RulesPtr rules, 711706f2543Smrg XkbRF_MultiDefsPtr mdefs, 712706f2543Smrg XkbComponentNamesPtr names, 713706f2543Smrg int flags) 714706f2543Smrg{ 715706f2543Smrgint i; 716706f2543SmrgXkbRF_RulePtr rule; 717706f2543Smrgint skip; 718706f2543Smrg 719706f2543Smrg for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) { 720706f2543Smrg if ((rule->flags & flags) != flags) 721706f2543Smrg continue; 722706f2543Smrg skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules); 723706f2543Smrg if (skip && !(flags & XkbRF_Option)) { 724706f2543Smrg for ( ;(i < rules->num_rules) && (rule->number == skip); 725706f2543Smrg rule++, i++); 726706f2543Smrg rule--; i--; 727706f2543Smrg } 728706f2543Smrg } 729706f2543Smrg} 730706f2543Smrg 731706f2543Smrg/***====================================================================***/ 732706f2543Smrg 733706f2543Smrgstatic char * 734706f2543SmrgXkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs) 735706f2543Smrg{ 736706f2543Smrgchar *str, *outstr, *orig, *var; 737706f2543Smrgint len, ndx; 738706f2543Smrg 739706f2543Smrg orig= name; 740706f2543Smrg str= index(name,'%'); 741706f2543Smrg if (str==NULL) 742706f2543Smrg return name; 743706f2543Smrg len= strlen(name); 744706f2543Smrg while (str!=NULL) { 745706f2543Smrg char pfx= str[1]; 746706f2543Smrg int extra_len= 0; 747706f2543Smrg if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { 748706f2543Smrg extra_len= 1; 749706f2543Smrg str++; 750706f2543Smrg } 751706f2543Smrg else if (pfx=='(') { 752706f2543Smrg extra_len= 2; 753706f2543Smrg str++; 754706f2543Smrg } 755706f2543Smrg var = str + 1; 756706f2543Smrg str = get_index(var + 1, &ndx); 757706f2543Smrg if (ndx == -1) { 758706f2543Smrg str = index(str,'%'); 759706f2543Smrg continue; 760706f2543Smrg } 761706f2543Smrg if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) 762706f2543Smrg len+= strlen(mdefs->layout[ndx])+extra_len; 763706f2543Smrg else if ((*var=='m')&&mdefs->model) 764706f2543Smrg len+= strlen(mdefs->model)+extra_len; 765706f2543Smrg else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) 766706f2543Smrg len+= strlen(mdefs->variant[ndx])+extra_len; 767706f2543Smrg if ((pfx=='(')&&(*str==')')) { 768706f2543Smrg str++; 769706f2543Smrg } 770706f2543Smrg str= index(&str[0],'%'); 771706f2543Smrg } 772706f2543Smrg name= malloc(len+1); 773706f2543Smrg str= orig; 774706f2543Smrg outstr= name; 775706f2543Smrg while (*str!='\0') { 776706f2543Smrg if (str[0]=='%') { 777706f2543Smrg char pfx,sfx; 778706f2543Smrg str++; 779706f2543Smrg pfx= str[0]; 780706f2543Smrg sfx= '\0'; 781706f2543Smrg if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { 782706f2543Smrg str++; 783706f2543Smrg } 784706f2543Smrg else if (pfx=='(') { 785706f2543Smrg sfx= ')'; 786706f2543Smrg str++; 787706f2543Smrg } 788706f2543Smrg else pfx= '\0'; 789706f2543Smrg 790706f2543Smrg var = str; 791706f2543Smrg str = get_index(var + 1, &ndx); 792706f2543Smrg if (ndx == -1) { 793706f2543Smrg continue; 794706f2543Smrg } 795706f2543Smrg if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) { 796706f2543Smrg if (pfx) *outstr++= pfx; 797706f2543Smrg strcpy(outstr,mdefs->layout[ndx]); 798706f2543Smrg outstr+= strlen(mdefs->layout[ndx]); 799706f2543Smrg if (sfx) *outstr++= sfx; 800706f2543Smrg } 801706f2543Smrg else if ((*var=='m')&&(mdefs->model)) { 802706f2543Smrg if (pfx) *outstr++= pfx; 803706f2543Smrg strcpy(outstr,mdefs->model); 804706f2543Smrg outstr+= strlen(mdefs->model); 805706f2543Smrg if (sfx) *outstr++= sfx; 806706f2543Smrg } 807706f2543Smrg else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) { 808706f2543Smrg if (pfx) *outstr++= pfx; 809706f2543Smrg strcpy(outstr,mdefs->variant[ndx]); 810706f2543Smrg outstr+= strlen(mdefs->variant[ndx]); 811706f2543Smrg if (sfx) *outstr++= sfx; 812706f2543Smrg } 813706f2543Smrg if ((pfx=='(')&&(*str==')')) 814706f2543Smrg str++; 815706f2543Smrg } 816706f2543Smrg else { 817706f2543Smrg *outstr++= *str++; 818706f2543Smrg } 819706f2543Smrg } 820706f2543Smrg *outstr++= '\0'; 821706f2543Smrg if (orig!=name) 822706f2543Smrg free(orig); 823706f2543Smrg return name; 824706f2543Smrg} 825706f2543Smrg 826706f2543Smrg/***====================================================================***/ 827706f2543Smrg 828706f2543SmrgBool 829706f2543SmrgXkbRF_GetComponents( XkbRF_RulesPtr rules, 830706f2543Smrg XkbRF_VarDefsPtr defs, 831706f2543Smrg XkbComponentNamesPtr names) 832706f2543Smrg{ 833706f2543Smrg XkbRF_MultiDefsRec mdefs; 834706f2543Smrg 835706f2543Smrg MakeMultiDefs(&mdefs, defs); 836706f2543Smrg 837706f2543Smrg memset((char *)names, 0, sizeof(XkbComponentNamesRec)); 838706f2543Smrg XkbRF_ClearPartialMatches(rules); 839706f2543Smrg XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal); 840706f2543Smrg XkbRF_ApplyPartialMatches(rules, names); 841706f2543Smrg XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append); 842706f2543Smrg XkbRF_ApplyPartialMatches(rules, names); 843706f2543Smrg XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option); 844706f2543Smrg 845706f2543Smrg if (names->keycodes) 846706f2543Smrg names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs); 847706f2543Smrg if (names->symbols) 848706f2543Smrg names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs); 849706f2543Smrg if (names->types) 850706f2543Smrg names->types= XkbRF_SubstituteVars(names->types, &mdefs); 851706f2543Smrg if (names->compat) 852706f2543Smrg names->compat= XkbRF_SubstituteVars(names->compat, &mdefs); 853706f2543Smrg if (names->geometry) 854706f2543Smrg names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs); 855706f2543Smrg 856706f2543Smrg FreeMultiDefs(&mdefs); 857706f2543Smrg return (names->keycodes && names->symbols && names->types && 858706f2543Smrg names->compat && names->geometry); 859706f2543Smrg} 860706f2543Smrg 861706f2543Smrgstatic XkbRF_RulePtr 862706f2543SmrgXkbRF_AddRule(XkbRF_RulesPtr rules) 863706f2543Smrg{ 864706f2543Smrg if (rules->sz_rules<1) { 865706f2543Smrg rules->sz_rules= 16; 866706f2543Smrg rules->num_rules= 0; 867706f2543Smrg rules->rules= calloc(rules->sz_rules, sizeof(XkbRF_RuleRec)); 868706f2543Smrg } 869706f2543Smrg else if (rules->num_rules>=rules->sz_rules) { 870706f2543Smrg rules->sz_rules*= 2; 871706f2543Smrg rules->rules= realloc(rules->rules, 872706f2543Smrg rules->sz_rules * sizeof(XkbRF_RuleRec)); 873706f2543Smrg } 874706f2543Smrg if (!rules->rules) { 875706f2543Smrg rules->sz_rules= rules->num_rules= 0; 876706f2543Smrg DebugF("Allocation failure in XkbRF_AddRule\n"); 877706f2543Smrg return NULL; 878706f2543Smrg } 879706f2543Smrg memset((char *)&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec)); 880706f2543Smrg return &rules->rules[rules->num_rules++]; 881706f2543Smrg} 882706f2543Smrg 883706f2543Smrgstatic XkbRF_GroupPtr 884706f2543SmrgXkbRF_AddGroup(XkbRF_RulesPtr rules) 885706f2543Smrg{ 886706f2543Smrg if (rules->sz_groups<1) { 887706f2543Smrg rules->sz_groups= 16; 888706f2543Smrg rules->num_groups= 0; 889706f2543Smrg rules->groups= calloc(rules->sz_groups, sizeof(XkbRF_GroupRec)); 890706f2543Smrg } 891706f2543Smrg else if (rules->num_groups >= rules->sz_groups) { 892706f2543Smrg rules->sz_groups *= 2; 893706f2543Smrg rules->groups= realloc(rules->groups, 894706f2543Smrg rules->sz_groups * sizeof(XkbRF_GroupRec)); 895706f2543Smrg } 896706f2543Smrg if (!rules->groups) { 897706f2543Smrg rules->sz_groups= rules->num_groups= 0; 898706f2543Smrg return NULL; 899706f2543Smrg } 900706f2543Smrg 901706f2543Smrg memset((char *)&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec)); 902706f2543Smrg return &rules->groups[rules->num_groups++]; 903706f2543Smrg} 904706f2543Smrg 905706f2543SmrgBool 906706f2543SmrgXkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules) 907706f2543Smrg{ 908706f2543SmrgInputLine line; 909706f2543SmrgRemapSpec remap; 910706f2543SmrgXkbRF_RuleRec trule,*rule; 911706f2543SmrgXkbRF_GroupRec tgroup,*group; 912706f2543Smrg 913706f2543Smrg if (!(rules && file)) 914706f2543Smrg return FALSE; 915706f2543Smrg memset((char *)&remap, 0, sizeof(RemapSpec)); 916706f2543Smrg memset((char *)&tgroup, 0, sizeof(XkbRF_GroupRec)); 917706f2543Smrg InitInputLine(&line); 918706f2543Smrg while (GetInputLine(file,&line,TRUE)) { 919706f2543Smrg if (CheckLine(&line,&remap,&trule,&tgroup)) { 920706f2543Smrg if (tgroup.number) { 921706f2543Smrg if ((group= XkbRF_AddGroup(rules))!=NULL) { 922706f2543Smrg *group= tgroup; 923706f2543Smrg memset((char *)&tgroup, 0, sizeof(XkbRF_GroupRec)); 924706f2543Smrg } 925706f2543Smrg } else { 926706f2543Smrg if ((rule= XkbRF_AddRule(rules))!=NULL) { 927706f2543Smrg *rule= trule; 928706f2543Smrg memset((char *)&trule, 0, sizeof(XkbRF_RuleRec)); 929706f2543Smrg } 930706f2543Smrg } 931706f2543Smrg } 932706f2543Smrg line.num_line= 0; 933706f2543Smrg } 934706f2543Smrg FreeInputLine(&line); 935706f2543Smrg return TRUE; 936706f2543Smrg} 937706f2543Smrg 938706f2543SmrgBool 939706f2543SmrgXkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules) 940706f2543Smrg{ 941706f2543SmrgFILE * file; 942706f2543Smrgchar buf[PATH_MAX]; 943706f2543SmrgBool ok; 944706f2543Smrg 945706f2543Smrg if ((!base)||(!rules)) 946706f2543Smrg return FALSE; 947706f2543Smrg if (locale) { 948706f2543Smrg if (strlen(base)+strlen(locale)+2 > PATH_MAX) 949706f2543Smrg return FALSE; 950706f2543Smrg sprintf(buf,"%s-%s", base, locale); 951706f2543Smrg } 952706f2543Smrg else { 953706f2543Smrg if (strlen(base)+1 > PATH_MAX) 954706f2543Smrg return FALSE; 955706f2543Smrg strcpy(buf,base); 956706f2543Smrg } 957706f2543Smrg 958706f2543Smrg file= fopen(buf, "r"); 959706f2543Smrg if ((!file)&&(locale)) { /* fallback if locale was specified */ 960706f2543Smrg strcpy(buf,base); 961706f2543Smrg file= fopen(buf, "r"); 962706f2543Smrg } 963706f2543Smrg if (!file) 964706f2543Smrg return FALSE; 965706f2543Smrg ok= XkbRF_LoadRules(file,rules); 966706f2543Smrg fclose(file); 967706f2543Smrg return ok; 968706f2543Smrg} 969706f2543Smrg 970706f2543Smrg/***====================================================================***/ 971706f2543Smrg 972706f2543SmrgXkbRF_RulesPtr 973706f2543SmrgXkbRF_Create(void) 974706f2543Smrg{ 975706f2543Smrg return calloc(1, sizeof( XkbRF_RulesRec)); 976706f2543Smrg} 977706f2543Smrg 978706f2543Smrg/***====================================================================***/ 979706f2543Smrg 980706f2543Smrgvoid 981706f2543SmrgXkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules) 982706f2543Smrg{ 983706f2543Smrgint i; 984706f2543SmrgXkbRF_RulePtr rule; 985706f2543SmrgXkbRF_GroupPtr group; 986706f2543Smrg 987706f2543Smrg if (!rules) 988706f2543Smrg return; 989706f2543Smrg if (rules->rules) { 990706f2543Smrg for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { 991706f2543Smrg free(rule->model); 992706f2543Smrg free(rule->layout); 993706f2543Smrg free(rule->variant); 994706f2543Smrg free(rule->option); 995706f2543Smrg free(rule->keycodes); 996706f2543Smrg free(rule->symbols); 997706f2543Smrg free(rule->types); 998706f2543Smrg free(rule->compat); 999706f2543Smrg free(rule->geometry); 1000706f2543Smrg memset((char *)rule, 0, sizeof(XkbRF_RuleRec)); 1001706f2543Smrg } 1002706f2543Smrg free(rules->rules); 1003706f2543Smrg rules->num_rules= rules->sz_rules= 0; 1004706f2543Smrg rules->rules= NULL; 1005706f2543Smrg } 1006706f2543Smrg 1007706f2543Smrg if (rules->groups) { 1008706f2543Smrg for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) { 1009706f2543Smrg free(group->name); 1010706f2543Smrg free(group->words); 1011706f2543Smrg } 1012706f2543Smrg free(rules->groups); 1013706f2543Smrg rules->num_groups= 0; 1014706f2543Smrg rules->groups= NULL; 1015706f2543Smrg } 1016706f2543Smrg if (freeRules) 1017706f2543Smrg free(rules); 1018706f2543Smrg return; 1019706f2543Smrg} 1020