maprules.c revision 706f2543
1/************************************************************ 2 Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc. 3 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. 15 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. 24 25 ********************************************************/ 26 27#ifdef HAVE_DIX_CONFIG_H 28#include <dix-config.h> 29#endif 30 31#include <stdio.h> 32#include <ctype.h> 33#include <stdlib.h> 34 35#define X_INCLUDE_STRING_H 36#define XOS_USE_NO_LOCKING 37#include <X11/Xos_r.h> 38 39#include <X11/Xproto.h> 40#include <X11/X.h> 41#include <X11/Xos.h> 42#include <X11/Xfuncs.h> 43#include <X11/Xatom.h> 44#include <X11/keysym.h> 45#include "misc.h" 46#include "inputstr.h" 47#include "dix.h" 48#include "os.h" 49#include "xkbstr.h" 50#define XKBSRV_NEED_FILE_FUNCS 51#include <xkbsrv.h> 52 53/***====================================================================***/ 54 55 56 57#define DFLT_LINE_SIZE 128 58 59typedef struct { 60 int line_num; 61 int sz_line; 62 int num_line; 63 char buf[DFLT_LINE_SIZE]; 64 char * line; 65} InputLine; 66 67static void 68InitInputLine(InputLine *line) 69{ 70 line->line_num= 1; 71 line->num_line= 0; 72 line->sz_line= DFLT_LINE_SIZE; 73 line->line= line->buf; 74 return; 75} 76 77static void 78FreeInputLine(InputLine *line) 79{ 80 if (line->line!=line->buf) 81 free(line->line); 82 line->line_num= 1; 83 line->num_line= 0; 84 line->sz_line= DFLT_LINE_SIZE; 85 line->line= line->buf; 86 return; 87} 88 89static int 90InputLineAddChar(InputLine *line,int ch) 91{ 92 if (line->num_line>=line->sz_line) { 93 if (line->line==line->buf) { 94 line->line= malloc(line->sz_line*2); 95 memcpy(line->line,line->buf,line->sz_line); 96 } 97 else { 98 line->line= realloc((char *)line->line,line->sz_line*2); 99 } 100 line->sz_line*= 2; 101 } 102 line->line[line->num_line++]= ch; 103 return ch; 104} 105 106#define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\ 107 (int)((l)->line[(l)->num_line++]= (c)):\ 108 InputLineAddChar(l,c)) 109 110static Bool 111GetInputLine(FILE *file,InputLine *line,Bool checkbang) 112{ 113int ch; 114Bool endOfFile,spacePending,slashPending,inComment; 115 116 endOfFile= FALSE; 117 while ((!endOfFile)&&(line->num_line==0)) { 118 spacePending= slashPending= inComment= FALSE; 119 while (((ch=getc(file))!='\n')&&(ch!=EOF)) { 120 if (ch=='\\') { 121 if ((ch=getc(file))==EOF) 122 break; 123 if (ch=='\n') { 124 inComment= FALSE; 125 ch= ' '; 126 line->line_num++; 127 } 128 } 129 if (inComment) 130 continue; 131 if (ch=='/') { 132 if (slashPending) { 133 inComment= TRUE; 134 slashPending= FALSE; 135 } 136 else { 137 slashPending= TRUE; 138 } 139 continue; 140 } 141 else if (slashPending) { 142 if (spacePending) { 143 ADD_CHAR(line,' '); 144 spacePending= FALSE; 145 } 146 ADD_CHAR(line,'/'); 147 slashPending= FALSE; 148 } 149 if (isspace(ch)) { 150 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) { 151 ch= getc(file); 152 } 153 if (ch==EOF) 154 break; 155 if ((ch!='\n')&&(line->num_line>0)) 156 spacePending= TRUE; 157 ungetc(ch,file); 158 } 159 else { 160 if (spacePending) { 161 ADD_CHAR(line,' '); 162 spacePending= FALSE; 163 } 164 if (checkbang && ch=='!') { 165 if (line->num_line!=0) { 166 DebugF("The '!' legal only at start of line\n"); 167 DebugF("Line containing '!' ignored\n"); 168 line->num_line= 0; 169 inComment= 0; 170 break; 171 } 172 173 } 174 ADD_CHAR(line,ch); 175 } 176 } 177 if (ch==EOF) 178 endOfFile= TRUE; 179/* else line->num_line++;*/ 180 } 181 if ((line->num_line==0)&&(endOfFile)) 182 return FALSE; 183 ADD_CHAR(line,'\0'); 184 return TRUE; 185} 186 187/***====================================================================***/ 188 189#define MODEL 0 190#define LAYOUT 1 191#define VARIANT 2 192#define OPTION 3 193#define KEYCODES 4 194#define SYMBOLS 5 195#define TYPES 6 196#define COMPAT 7 197#define GEOMETRY 8 198#define MAX_WORDS 9 199 200#define PART_MASK 0x000F 201#define COMPONENT_MASK 0x03F0 202 203static char * cname[MAX_WORDS] = { 204 "model", "layout", "variant", "option", 205 "keycodes", "symbols", "types", "compat", "geometry" 206}; 207 208typedef struct _RemapSpec { 209 int number; 210 int num_remap; 211 struct { 212 int word; 213 int index; 214 } remap[MAX_WORDS]; 215} RemapSpec; 216 217typedef struct _FileSpec { 218 char * name[MAX_WORDS]; 219 struct _FileSpec * pending; 220} FileSpec; 221 222typedef struct { 223 char * model; 224 char * layout[XkbNumKbdGroups+1]; 225 char * variant[XkbNumKbdGroups+1]; 226 char * options; 227} XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr; 228 229#define NDX_BUFF_SIZE 4 230 231/***====================================================================***/ 232 233static char* 234get_index(char *str, int *ndx) 235{ 236 char ndx_buf[NDX_BUFF_SIZE]; 237 char *end; 238 239 if (*str != '[') { 240 *ndx = 0; 241 return str; 242 } 243 str++; 244 end = strchr(str, ']'); 245 if (end == NULL) { 246 *ndx = -1; 247 return str - 1; 248 } 249 if ( (end - str) >= NDX_BUFF_SIZE) { 250 *ndx = -1; 251 return end + 1; 252 } 253 strncpy(ndx_buf, str, end - str); 254 ndx_buf[end - str] = '\0'; 255 *ndx = atoi(ndx_buf); 256 return end + 1; 257} 258 259static void 260SetUpRemap(InputLine *line,RemapSpec *remap) 261{ 262char * tok,*str; 263unsigned present, l_ndx_present, v_ndx_present; 264register int i; 265int len, ndx; 266_Xstrtokparams strtok_buf; 267Bool found; 268 269 270 l_ndx_present = v_ndx_present = present= 0; 271 str= &line->line[1]; 272 len = remap->number; 273 memset((char *)remap, 0, sizeof(RemapSpec)); 274 remap->number = len; 275 while ((tok=_XStrtok(str," ",strtok_buf))!=NULL) { 276 found= FALSE; 277 str= NULL; 278 if (strcmp(tok,"=")==0) 279 continue; 280 for (i=0;i<MAX_WORDS;i++) { 281 len = strlen(cname[i]); 282 if (strncmp(cname[i],tok,len)==0) { 283 if(strlen(tok) > len) { 284 char *end = get_index(tok+len, &ndx); 285 if ((i != LAYOUT && i != VARIANT) || 286 *end != '\0' || ndx == -1) 287 break; 288 if (ndx < 1 || ndx > XkbNumKbdGroups) { 289 DebugF("Illegal %s index: %d\n", cname[i], ndx); 290 DebugF("Index must be in range 1..%d\n", 291 XkbNumKbdGroups); 292 break; 293 } 294 } else { 295 ndx = 0; 296 } 297 found= TRUE; 298 if (present&(1<<i)) { 299 if ((i == LAYOUT && l_ndx_present&(1<<ndx)) || 300 (i == VARIANT && v_ndx_present&(1<<ndx)) ) { 301 DebugF("Component \"%s\" listed twice\n",tok); 302 DebugF("Second definition ignored\n"); 303 break; 304 } 305 } 306 present |= (1<<i); 307 if (i == LAYOUT) 308 l_ndx_present |= 1 << ndx; 309 if (i == VARIANT) 310 v_ndx_present |= 1 << ndx; 311 remap->remap[remap->num_remap].word= i; 312 remap->remap[remap->num_remap++].index= ndx; 313 break; 314 } 315 } 316 if (!found) { 317 fprintf(stderr,"Unknown component \"%s\" ignored\n",tok); 318 } 319 } 320 if ((present&PART_MASK)==0) { 321 unsigned mask= PART_MASK; 322 ErrorF("Mapping needs at least one of "); 323 for (i=0; (i<MAX_WORDS); i++) { 324 if ((1L<<i)&mask) { 325 mask&= ~(1L<<i); 326 if (mask) DebugF("\"%s,\" ",cname[i]); 327 else DebugF("or \"%s\"\n",cname[i]); 328 } 329 } 330 DebugF("Illegal mapping ignored\n"); 331 remap->num_remap= 0; 332 return; 333 } 334 if ((present&COMPONENT_MASK)==0) { 335 DebugF("Mapping needs at least one component\n"); 336 DebugF("Illegal mapping ignored\n"); 337 remap->num_remap= 0; 338 return; 339 } 340 remap->number++; 341 return; 342} 343 344static Bool 345MatchOneOf(char *wanted,char *vals_defined) 346{ 347char *str,*next; 348int want_len= strlen(wanted); 349 350 for (str=vals_defined,next=NULL;str!=NULL;str=next) { 351 int len; 352 next= strchr(str,','); 353 if (next) { 354 len= next-str; 355 next++; 356 } 357 else { 358 len= strlen(str); 359 } 360 if ((len==want_len)&&(strncmp(wanted,str,len)==0)) 361 return TRUE; 362 } 363 return FALSE; 364} 365 366/***====================================================================***/ 367 368static Bool 369CheckLine( InputLine * line, 370 RemapSpec * remap, 371 XkbRF_RulePtr rule, 372 XkbRF_GroupPtr group) 373{ 374char * str,*tok; 375register int nread, i; 376FileSpec tmp; 377_Xstrtokparams strtok_buf; 378Bool append = FALSE; 379 380 if (line->line[0]=='!') { 381 if (line->line[1] == '$' || 382 (line->line[1] == ' ' && line->line[2] == '$')) { 383 char *gname = strchr(line->line, '$'); 384 char *words = strchr(gname, ' '); 385 if(!words) 386 return FALSE; 387 *words++ = '\0'; 388 for (; *words; words++) { 389 if (*words != '=' && *words != ' ') 390 break; 391 } 392 if (*words == '\0') 393 return FALSE; 394 group->name = _XkbDupString(gname); 395 group->words = _XkbDupString(words); 396 for (i = 1, words = group->words; *words; words++) { 397 if ( *words == ' ') { 398 *words++ = '\0'; 399 i++; 400 } 401 } 402 group->number = i; 403 return TRUE; 404 } else { 405 SetUpRemap(line,remap); 406 return FALSE; 407 } 408 } 409 410 if (remap->num_remap==0) { 411 DebugF("Must have a mapping before first line of data\n"); 412 DebugF("Illegal line of data ignored\n"); 413 return FALSE; 414 } 415 memset((char *)&tmp, 0, sizeof(FileSpec)); 416 str= line->line; 417 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) { 418 str= NULL; 419 if (strcmp(tok,"=")==0) { 420 nread--; 421 continue; 422 } 423 if (nread>remap->num_remap) { 424 DebugF("Too many words on a line\n"); 425 DebugF("Extra word \"%s\" ignored\n",tok); 426 continue; 427 } 428 tmp.name[remap->remap[nread].word]= tok; 429 if (*tok == '+' || *tok == '|') 430 append = TRUE; 431 } 432 if (nread<remap->num_remap) { 433 DebugF("Too few words on a line: %s\n", line->line); 434 DebugF("line ignored\n"); 435 return FALSE; 436 } 437 438 rule->flags= 0; 439 rule->number = remap->number; 440 if (tmp.name[OPTION]) 441 rule->flags|= XkbRF_Option; 442 else if (append) 443 rule->flags|= XkbRF_Append; 444 else 445 rule->flags|= XkbRF_Normal; 446 rule->model= _XkbDupString(tmp.name[MODEL]); 447 rule->layout= _XkbDupString(tmp.name[LAYOUT]); 448 rule->variant= _XkbDupString(tmp.name[VARIANT]); 449 rule->option= _XkbDupString(tmp.name[OPTION]); 450 451 rule->keycodes= _XkbDupString(tmp.name[KEYCODES]); 452 rule->symbols= _XkbDupString(tmp.name[SYMBOLS]); 453 rule->types= _XkbDupString(tmp.name[TYPES]); 454 rule->compat= _XkbDupString(tmp.name[COMPAT]); 455 rule->geometry= _XkbDupString(tmp.name[GEOMETRY]); 456 457 rule->layout_num = rule->variant_num = 0; 458 for (i = 0; i < nread; i++) { 459 if (remap->remap[i].index) { 460 if (remap->remap[i].word == LAYOUT) 461 rule->layout_num = remap->remap[i].index; 462 if (remap->remap[i].word == VARIANT) 463 rule->variant_num = remap->remap[i].index; 464 } 465 } 466 return TRUE; 467} 468 469static char * 470_Concat(char *str1,char *str2) 471{ 472int len; 473 474 if ((!str1)||(!str2)) 475 return str1; 476 len= strlen(str1)+strlen(str2)+1; 477 str1= realloc(str1,len * sizeof(char)); 478 if (str1) 479 strcat(str1,str2); 480 return str1; 481} 482 483static void 484squeeze_spaces(char *p1) 485{ 486 char *p2; 487 for (p2 = p1; *p2; p2++) { 488 *p1 = *p2; 489 if (*p1 != ' ') p1++; 490 } 491 *p1 = '\0'; 492} 493 494static Bool 495MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs) 496{ 497 498 memset((char *)mdefs, 0, sizeof(XkbRF_MultiDefsRec)); 499 mdefs->model = defs->model; 500 mdefs->options = _XkbDupString(defs->options); 501 if (mdefs->options) squeeze_spaces(mdefs->options); 502 503 if (defs->layout) { 504 if (!strchr(defs->layout, ',')) { 505 mdefs->layout[0] = defs->layout; 506 } else { 507 char *p; 508 int i; 509 mdefs->layout[1] = _XkbDupString(defs->layout); 510 if (mdefs->layout[1] == NULL) 511 return FALSE; 512 squeeze_spaces(mdefs->layout[1]); 513 p = mdefs->layout[1]; 514 for (i = 2; i <= XkbNumKbdGroups; i++) { 515 if ((p = strchr(p, ','))) { 516 *p++ = '\0'; 517 mdefs->layout[i] = p; 518 } else { 519 break; 520 } 521 } 522 if (p && (p = strchr(p, ','))) 523 *p = '\0'; 524 } 525 } 526 527 if (defs->variant) { 528 if (!strchr(defs->variant, ',')) { 529 mdefs->variant[0] = defs->variant; 530 } else { 531 char *p; 532 int i; 533 mdefs->variant[1] = _XkbDupString(defs->variant); 534 if (mdefs->variant[1] == NULL) 535 return FALSE; 536 squeeze_spaces(mdefs->variant[1]); 537 p = mdefs->variant[1]; 538 for (i = 2; i <= XkbNumKbdGroups; i++) { 539 if ((p = strchr(p, ','))) { 540 *p++ = '\0'; 541 mdefs->variant[i] = p; 542 } else { 543 break; 544 } 545 } 546 if (p && (p = strchr(p, ','))) 547 *p = '\0'; 548 } 549 } 550 return TRUE; 551} 552 553static void 554FreeMultiDefs(XkbRF_MultiDefsPtr defs) 555{ 556 free(defs->options); 557 free(defs->layout[1]); 558 free(defs->variant[1]); 559} 560 561static void 562Apply(char *src, char **dst) 563{ 564 if (src) { 565 if (*src == '+' || *src == '!') { 566 *dst= _Concat(*dst, src); 567 } else { 568 if (*dst == NULL) 569 *dst= _XkbDupString(src); 570 } 571 } 572} 573 574static void 575XkbRF_ApplyRule( XkbRF_RulePtr rule, 576 XkbComponentNamesPtr names) 577{ 578 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */ 579 580 Apply(rule->keycodes, &names->keycodes); 581 Apply(rule->symbols, &names->symbols); 582 Apply(rule->types, &names->types); 583 Apply(rule->compat, &names->compat); 584 Apply(rule->geometry, &names->geometry); 585} 586 587static Bool 588CheckGroup( XkbRF_RulesPtr rules, 589 char * group_name, 590 char * name) 591{ 592 int i; 593 char *p; 594 XkbRF_GroupPtr group; 595 596 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) { 597 if (! strcmp(group->name, group_name)) { 598 break; 599 } 600 } 601 if (i == rules->num_groups) 602 return FALSE; 603 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) { 604 if (! strcmp(p, name)) { 605 return TRUE; 606 } 607 } 608 return FALSE; 609} 610 611static int 612XkbRF_CheckApplyRule( XkbRF_RulePtr rule, 613 XkbRF_MultiDefsPtr mdefs, 614 XkbComponentNamesPtr names, 615 XkbRF_RulesPtr rules) 616{ 617 Bool pending = FALSE; 618 619 if (rule->model != NULL) { 620 if(mdefs->model == NULL) 621 return 0; 622 if (strcmp(rule->model, "*") == 0) { 623 pending = TRUE; 624 } else { 625 if (rule->model[0] == '$') { 626 if (!CheckGroup(rules, rule->model, mdefs->model)) 627 return 0; 628 } else { 629 if (strcmp(rule->model, mdefs->model) != 0) 630 return 0; 631 } 632 } 633 } 634 if (rule->option != NULL) { 635 if (mdefs->options == NULL) 636 return 0; 637 if ((!MatchOneOf(rule->option,mdefs->options))) 638 return 0; 639 } 640 641 if (rule->layout != NULL) { 642 if(mdefs->layout[rule->layout_num] == NULL || 643 *mdefs->layout[rule->layout_num] == '\0') 644 return 0; 645 if (strcmp(rule->layout, "*") == 0) { 646 pending = TRUE; 647 } else { 648 if (rule->layout[0] == '$') { 649 if (!CheckGroup(rules, rule->layout, 650 mdefs->layout[rule->layout_num])) 651 return 0; 652 } else { 653 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0) 654 return 0; 655 } 656 } 657 } 658 if (rule->variant != NULL) { 659 if (mdefs->variant[rule->variant_num] == NULL || 660 *mdefs->variant[rule->variant_num] == '\0') 661 return 0; 662 if (strcmp(rule->variant, "*") == 0) { 663 pending = TRUE; 664 } else { 665 if (rule->variant[0] == '$') { 666 if (!CheckGroup(rules, rule->variant, 667 mdefs->variant[rule->variant_num])) 668 return 0; 669 } else { 670 if (strcmp(rule->variant, 671 mdefs->variant[rule->variant_num]) != 0) 672 return 0; 673 } 674 } 675 } 676 if (pending) { 677 rule->flags|= XkbRF_PendingMatch; 678 return rule->number; 679 } 680 /* exact match, apply it now */ 681 XkbRF_ApplyRule(rule,names); 682 return rule->number; 683} 684 685static void 686XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules) 687{ 688register int i; 689XkbRF_RulePtr rule; 690 691 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { 692 rule->flags&= ~XkbRF_PendingMatch; 693 } 694} 695 696static void 697XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names) 698{ 699int i; 700XkbRF_RulePtr rule; 701 702 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) { 703 if ((rule->flags&XkbRF_PendingMatch)==0) 704 continue; 705 XkbRF_ApplyRule(rule,names); 706 } 707} 708 709static void 710XkbRF_CheckApplyRules( XkbRF_RulesPtr rules, 711 XkbRF_MultiDefsPtr mdefs, 712 XkbComponentNamesPtr names, 713 int flags) 714{ 715int i; 716XkbRF_RulePtr rule; 717int skip; 718 719 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) { 720 if ((rule->flags & flags) != flags) 721 continue; 722 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules); 723 if (skip && !(flags & XkbRF_Option)) { 724 for ( ;(i < rules->num_rules) && (rule->number == skip); 725 rule++, i++); 726 rule--; i--; 727 } 728 } 729} 730 731/***====================================================================***/ 732 733static char * 734XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs) 735{ 736char *str, *outstr, *orig, *var; 737int len, ndx; 738 739 orig= name; 740 str= index(name,'%'); 741 if (str==NULL) 742 return name; 743 len= strlen(name); 744 while (str!=NULL) { 745 char pfx= str[1]; 746 int extra_len= 0; 747 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { 748 extra_len= 1; 749 str++; 750 } 751 else if (pfx=='(') { 752 extra_len= 2; 753 str++; 754 } 755 var = str + 1; 756 str = get_index(var + 1, &ndx); 757 if (ndx == -1) { 758 str = index(str,'%'); 759 continue; 760 } 761 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) 762 len+= strlen(mdefs->layout[ndx])+extra_len; 763 else if ((*var=='m')&&mdefs->model) 764 len+= strlen(mdefs->model)+extra_len; 765 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) 766 len+= strlen(mdefs->variant[ndx])+extra_len; 767 if ((pfx=='(')&&(*str==')')) { 768 str++; 769 } 770 str= index(&str[0],'%'); 771 } 772 name= malloc(len+1); 773 str= orig; 774 outstr= name; 775 while (*str!='\0') { 776 if (str[0]=='%') { 777 char pfx,sfx; 778 str++; 779 pfx= str[0]; 780 sfx= '\0'; 781 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { 782 str++; 783 } 784 else if (pfx=='(') { 785 sfx= ')'; 786 str++; 787 } 788 else pfx= '\0'; 789 790 var = str; 791 str = get_index(var + 1, &ndx); 792 if (ndx == -1) { 793 continue; 794 } 795 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) { 796 if (pfx) *outstr++= pfx; 797 strcpy(outstr,mdefs->layout[ndx]); 798 outstr+= strlen(mdefs->layout[ndx]); 799 if (sfx) *outstr++= sfx; 800 } 801 else if ((*var=='m')&&(mdefs->model)) { 802 if (pfx) *outstr++= pfx; 803 strcpy(outstr,mdefs->model); 804 outstr+= strlen(mdefs->model); 805 if (sfx) *outstr++= sfx; 806 } 807 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) { 808 if (pfx) *outstr++= pfx; 809 strcpy(outstr,mdefs->variant[ndx]); 810 outstr+= strlen(mdefs->variant[ndx]); 811 if (sfx) *outstr++= sfx; 812 } 813 if ((pfx=='(')&&(*str==')')) 814 str++; 815 } 816 else { 817 *outstr++= *str++; 818 } 819 } 820 *outstr++= '\0'; 821 if (orig!=name) 822 free(orig); 823 return name; 824} 825 826/***====================================================================***/ 827 828Bool 829XkbRF_GetComponents( XkbRF_RulesPtr rules, 830 XkbRF_VarDefsPtr defs, 831 XkbComponentNamesPtr names) 832{ 833 XkbRF_MultiDefsRec mdefs; 834 835 MakeMultiDefs(&mdefs, defs); 836 837 memset((char *)names, 0, sizeof(XkbComponentNamesRec)); 838 XkbRF_ClearPartialMatches(rules); 839 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal); 840 XkbRF_ApplyPartialMatches(rules, names); 841 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append); 842 XkbRF_ApplyPartialMatches(rules, names); 843 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option); 844 845 if (names->keycodes) 846 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs); 847 if (names->symbols) 848 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs); 849 if (names->types) 850 names->types= XkbRF_SubstituteVars(names->types, &mdefs); 851 if (names->compat) 852 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs); 853 if (names->geometry) 854 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs); 855 856 FreeMultiDefs(&mdefs); 857 return (names->keycodes && names->symbols && names->types && 858 names->compat && names->geometry); 859} 860 861static XkbRF_RulePtr 862XkbRF_AddRule(XkbRF_RulesPtr rules) 863{ 864 if (rules->sz_rules<1) { 865 rules->sz_rules= 16; 866 rules->num_rules= 0; 867 rules->rules= calloc(rules->sz_rules, sizeof(XkbRF_RuleRec)); 868 } 869 else if (rules->num_rules>=rules->sz_rules) { 870 rules->sz_rules*= 2; 871 rules->rules= realloc(rules->rules, 872 rules->sz_rules * sizeof(XkbRF_RuleRec)); 873 } 874 if (!rules->rules) { 875 rules->sz_rules= rules->num_rules= 0; 876 DebugF("Allocation failure in XkbRF_AddRule\n"); 877 return NULL; 878 } 879 memset((char *)&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec)); 880 return &rules->rules[rules->num_rules++]; 881} 882 883static XkbRF_GroupPtr 884XkbRF_AddGroup(XkbRF_RulesPtr rules) 885{ 886 if (rules->sz_groups<1) { 887 rules->sz_groups= 16; 888 rules->num_groups= 0; 889 rules->groups= calloc(rules->sz_groups, sizeof(XkbRF_GroupRec)); 890 } 891 else if (rules->num_groups >= rules->sz_groups) { 892 rules->sz_groups *= 2; 893 rules->groups= realloc(rules->groups, 894 rules->sz_groups * sizeof(XkbRF_GroupRec)); 895 } 896 if (!rules->groups) { 897 rules->sz_groups= rules->num_groups= 0; 898 return NULL; 899 } 900 901 memset((char *)&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec)); 902 return &rules->groups[rules->num_groups++]; 903} 904 905Bool 906XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules) 907{ 908InputLine line; 909RemapSpec remap; 910XkbRF_RuleRec trule,*rule; 911XkbRF_GroupRec tgroup,*group; 912 913 if (!(rules && file)) 914 return FALSE; 915 memset((char *)&remap, 0, sizeof(RemapSpec)); 916 memset((char *)&tgroup, 0, sizeof(XkbRF_GroupRec)); 917 InitInputLine(&line); 918 while (GetInputLine(file,&line,TRUE)) { 919 if (CheckLine(&line,&remap,&trule,&tgroup)) { 920 if (tgroup.number) { 921 if ((group= XkbRF_AddGroup(rules))!=NULL) { 922 *group= tgroup; 923 memset((char *)&tgroup, 0, sizeof(XkbRF_GroupRec)); 924 } 925 } else { 926 if ((rule= XkbRF_AddRule(rules))!=NULL) { 927 *rule= trule; 928 memset((char *)&trule, 0, sizeof(XkbRF_RuleRec)); 929 } 930 } 931 } 932 line.num_line= 0; 933 } 934 FreeInputLine(&line); 935 return TRUE; 936} 937 938Bool 939XkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules) 940{ 941FILE * file; 942char buf[PATH_MAX]; 943Bool ok; 944 945 if ((!base)||(!rules)) 946 return FALSE; 947 if (locale) { 948 if (strlen(base)+strlen(locale)+2 > PATH_MAX) 949 return FALSE; 950 sprintf(buf,"%s-%s", base, locale); 951 } 952 else { 953 if (strlen(base)+1 > PATH_MAX) 954 return FALSE; 955 strcpy(buf,base); 956 } 957 958 file= fopen(buf, "r"); 959 if ((!file)&&(locale)) { /* fallback if locale was specified */ 960 strcpy(buf,base); 961 file= fopen(buf, "r"); 962 } 963 if (!file) 964 return FALSE; 965 ok= XkbRF_LoadRules(file,rules); 966 fclose(file); 967 return ok; 968} 969 970/***====================================================================***/ 971 972XkbRF_RulesPtr 973XkbRF_Create(void) 974{ 975 return calloc(1, sizeof( XkbRF_RulesRec)); 976} 977 978/***====================================================================***/ 979 980void 981XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules) 982{ 983int i; 984XkbRF_RulePtr rule; 985XkbRF_GroupPtr group; 986 987 if (!rules) 988 return; 989 if (rules->rules) { 990 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { 991 free(rule->model); 992 free(rule->layout); 993 free(rule->variant); 994 free(rule->option); 995 free(rule->keycodes); 996 free(rule->symbols); 997 free(rule->types); 998 free(rule->compat); 999 free(rule->geometry); 1000 memset((char *)rule, 0, sizeof(XkbRF_RuleRec)); 1001 } 1002 free(rules->rules); 1003 rules->num_rules= rules->sz_rules= 0; 1004 rules->rules= NULL; 1005 } 1006 1007 if (rules->groups) { 1008 for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) { 1009 free(group->name); 1010 free(group->words); 1011 } 1012 free(rules->groups); 1013 rules->num_groups= 0; 1014 rules->groups= NULL; 1015 } 1016 if (freeRules) 1017 free(rules); 1018 return; 1019} 1020