maprules.c revision 4642e01f
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#define NEED_EVENTS 40#include <X11/Xproto.h> 41#include <X11/X.h> 42#include <X11/Xos.h> 43#include <X11/Xfuncs.h> 44#include <X11/Xatom.h> 45#include <X11/keysym.h> 46#include "misc.h" 47#include "inputstr.h" 48#include "dix.h" 49#include "os.h" 50#include "xkbstr.h" 51#define XKBSRV_NEED_FILE_FUNCS 52#include <xkbsrv.h> 53 54/***====================================================================***/ 55 56#define DFLT_LINE_SIZE 128 57 58typedef struct { 59 int line_num; 60 int sz_line; 61 int num_line; 62 char buf[DFLT_LINE_SIZE]; 63 char * line; 64} InputLine; 65 66static void 67InitInputLine(InputLine *line) 68{ 69 line->line_num= 1; 70 line->num_line= 0; 71 line->sz_line= DFLT_LINE_SIZE; 72 line->line= line->buf; 73 return; 74} 75 76static void 77FreeInputLine(InputLine *line) 78{ 79 if (line->line!=line->buf) 80 _XkbFree(line->line); 81 line->line_num= 1; 82 line->num_line= 0; 83 line->sz_line= DFLT_LINE_SIZE; 84 line->line= line->buf; 85 return; 86} 87 88static int 89InputLineAddChar(InputLine *line,int ch) 90{ 91 if (line->num_line>=line->sz_line) { 92 if (line->line==line->buf) { 93 line->line= (char *)_XkbAlloc(line->sz_line*2); 94 memcpy(line->line,line->buf,line->sz_line); 95 } 96 else { 97 line->line=(char *)_XkbRealloc((char *)line->line,line->sz_line*2); 98 } 99 line->sz_line*= 2; 100 } 101 line->line[line->num_line++]= ch; 102 return ch; 103} 104 105#define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\ 106 (int)((l)->line[(l)->num_line++]= (c)):\ 107 InputLineAddChar(l,c)) 108 109static Bool 110GetInputLine(FILE *file,InputLine *line,Bool checkbang) 111{ 112int ch; 113Bool endOfFile,spacePending,slashPending,inComment; 114 115 endOfFile= False; 116 while ((!endOfFile)&&(line->num_line==0)) { 117 spacePending= slashPending= inComment= False; 118 while (((ch=getc(file))!='\n')&&(ch!=EOF)) { 119 if (ch=='\\') { 120 if ((ch=getc(file))==EOF) 121 break; 122 if (ch=='\n') { 123 inComment= False; 124 ch= ' '; 125 line->line_num++; 126 } 127 } 128 if (inComment) 129 continue; 130 if (ch=='/') { 131 if (slashPending) { 132 inComment= True; 133 slashPending= False; 134 } 135 else { 136 slashPending= True; 137 } 138 continue; 139 } 140 else if (slashPending) { 141 if (spacePending) { 142 ADD_CHAR(line,' '); 143 spacePending= False; 144 } 145 ADD_CHAR(line,'/'); 146 slashPending= False; 147 } 148 if (isspace(ch)) { 149 while (isspace(ch)&&(ch!='\n')&&(ch!=EOF)) { 150 ch= getc(file); 151 } 152 if (ch==EOF) 153 break; 154 if ((ch!='\n')&&(line->num_line>0)) 155 spacePending= True; 156 ungetc(ch,file); 157 } 158 else { 159 if (spacePending) { 160 ADD_CHAR(line,' '); 161 spacePending= False; 162 } 163 if (checkbang && ch=='!') { 164 if (line->num_line!=0) { 165 DebugF("The '!' legal only at start of line\n"); 166 DebugF("Line containing '!' ignored\n"); 167 line->num_line= 0; 168 inComment= 0; 169 break; 170 } 171 172 } 173 ADD_CHAR(line,ch); 174 } 175 } 176 if (ch==EOF) 177 endOfFile= True; 178/* else line->num_line++;*/ 179 } 180 if ((line->num_line==0)&&(endOfFile)) 181 return False; 182 ADD_CHAR(line,'\0'); 183 return True; 184} 185 186/***====================================================================***/ 187 188#define MODEL 0 189#define LAYOUT 1 190#define VARIANT 2 191#define OPTION 3 192#define KEYCODES 4 193#define SYMBOLS 5 194#define TYPES 6 195#define COMPAT 7 196#define GEOMETRY 8 197#define KEYMAP 9 198#define MAX_WORDS 10 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", "keymap" 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 bzero((char *)remap,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 if (((present&COMPONENT_MASK)&(1<<KEYMAP))&& 341 ((present&COMPONENT_MASK)!=(1<<KEYMAP))) { 342 DebugF("Keymap cannot appear with other components\n"); 343 DebugF("Illegal mapping ignored\n"); 344 remap->num_remap= 0; 345 return; 346 } 347 remap->number++; 348 return; 349} 350 351static Bool 352MatchOneOf(char *wanted,char *vals_defined) 353{ 354char *str,*next; 355int want_len= strlen(wanted); 356 357 for (str=vals_defined,next=NULL;str!=NULL;str=next) { 358 int len; 359 next= strchr(str,','); 360 if (next) { 361 len= next-str; 362 next++; 363 } 364 else { 365 len= strlen(str); 366 } 367 if ((len==want_len)&&(strncmp(wanted,str,len)==0)) 368 return True; 369 } 370 return False; 371} 372 373/***====================================================================***/ 374 375static Bool 376CheckLine( InputLine * line, 377 RemapSpec * remap, 378 XkbRF_RulePtr rule, 379 XkbRF_GroupPtr group) 380{ 381char * str,*tok; 382register int nread, i; 383FileSpec tmp; 384_Xstrtokparams strtok_buf; 385Bool append = False; 386 387 if (line->line[0]=='!') { 388 if (line->line[1] == '$' || 389 (line->line[1] == ' ' && line->line[2] == '$')) { 390 char *gname = strchr(line->line, '$'); 391 char *words = strchr(gname, ' '); 392 if(!words) 393 return False; 394 *words++ = '\0'; 395 for (; *words; words++) { 396 if (*words != '=' && *words != ' ') 397 break; 398 } 399 if (*words == '\0') 400 return False; 401 group->name = _XkbDupString(gname); 402 group->words = _XkbDupString(words); 403 for (i = 1, words = group->words; *words; words++) { 404 if ( *words == ' ') { 405 *words++ = '\0'; 406 i++; 407 } 408 } 409 group->number = i; 410 return True; 411 } else { 412 SetUpRemap(line,remap); 413 return False; 414 } 415 } 416 417 if (remap->num_remap==0) { 418 DebugF("Must have a mapping before first line of data\n"); 419 DebugF("Illegal line of data ignored\n"); 420 return False; 421 } 422 bzero((char *)&tmp,sizeof(FileSpec)); 423 str= line->line; 424 for (nread= 0;(tok=_XStrtok(str," ",strtok_buf))!=NULL;nread++) { 425 str= NULL; 426 if (strcmp(tok,"=")==0) { 427 nread--; 428 continue; 429 } 430 if (nread>remap->num_remap) { 431 DebugF("Too many words on a line\n"); 432 DebugF("Extra word \"%s\" ignored\n",tok); 433 continue; 434 } 435 tmp.name[remap->remap[nread].word]= tok; 436 if (*tok == '+' || *tok == '|') 437 append = True; 438 } 439 if (nread<remap->num_remap) { 440 DebugF("Too few words on a line: %s\n", line->line); 441 DebugF("line ignored\n"); 442 return False; 443 } 444 445 rule->flags= 0; 446 rule->number = remap->number; 447 if (tmp.name[OPTION]) 448 rule->flags|= XkbRF_Option; 449 else if (append) 450 rule->flags|= XkbRF_Append; 451 else 452 rule->flags|= XkbRF_Normal; 453 rule->model= _XkbDupString(tmp.name[MODEL]); 454 rule->layout= _XkbDupString(tmp.name[LAYOUT]); 455 rule->variant= _XkbDupString(tmp.name[VARIANT]); 456 rule->option= _XkbDupString(tmp.name[OPTION]); 457 458 rule->keycodes= _XkbDupString(tmp.name[KEYCODES]); 459 rule->symbols= _XkbDupString(tmp.name[SYMBOLS]); 460 rule->types= _XkbDupString(tmp.name[TYPES]); 461 rule->compat= _XkbDupString(tmp.name[COMPAT]); 462 rule->geometry= _XkbDupString(tmp.name[GEOMETRY]); 463 rule->keymap= NULL; 464 465 rule->layout_num = rule->variant_num = 0; 466 for (i = 0; i < nread; i++) { 467 if (remap->remap[i].index) { 468 if (remap->remap[i].word == LAYOUT) 469 rule->layout_num = remap->remap[i].index; 470 if (remap->remap[i].word == VARIANT) 471 rule->variant_num = remap->remap[i].index; 472 } 473 } 474 return True; 475} 476 477static char * 478_Concat(char *str1,char *str2) 479{ 480int len; 481 482 if ((!str1)||(!str2)) 483 return str1; 484 len= strlen(str1)+strlen(str2)+1; 485 str1= _XkbTypedRealloc(str1,len,char); 486 if (str1) 487 strcat(str1,str2); 488 return str1; 489} 490 491static void 492squeeze_spaces(char *p1) 493{ 494 char *p2; 495 for (p2 = p1; *p2; p2++) { 496 *p1 = *p2; 497 if (*p1 != ' ') p1++; 498 } 499 *p1 = '\0'; 500} 501 502static Bool 503MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs) 504{ 505 506 bzero((char *)mdefs,sizeof(XkbRF_MultiDefsRec)); 507 mdefs->model = defs->model; 508 mdefs->options = _XkbDupString(defs->options); 509 if (mdefs->options) squeeze_spaces(mdefs->options); 510 511 if (defs->layout) { 512 if (!strchr(defs->layout, ',')) { 513 mdefs->layout[0] = defs->layout; 514 } else { 515 char *p; 516 int i; 517 mdefs->layout[1] = _XkbDupString(defs->layout); 518 if (mdefs->layout[1] == NULL) 519 return False; 520 squeeze_spaces(mdefs->layout[1]); 521 p = mdefs->layout[1]; 522 for (i = 2; i <= XkbNumKbdGroups; i++) { 523 if ((p = strchr(p, ','))) { 524 *p++ = '\0'; 525 mdefs->layout[i] = p; 526 } else { 527 break; 528 } 529 } 530 if (p && (p = strchr(p, ','))) 531 *p = '\0'; 532 } 533 } 534 535 if (defs->variant) { 536 if (!strchr(defs->variant, ',')) { 537 mdefs->variant[0] = defs->variant; 538 } else { 539 char *p; 540 int i; 541 mdefs->variant[1] = _XkbDupString(defs->variant); 542 if (mdefs->variant[1] == NULL) 543 return False; 544 squeeze_spaces(mdefs->variant[1]); 545 p = mdefs->variant[1]; 546 for (i = 2; i <= XkbNumKbdGroups; i++) { 547 if ((p = strchr(p, ','))) { 548 *p++ = '\0'; 549 mdefs->variant[i] = p; 550 } else { 551 break; 552 } 553 } 554 if (p && (p = strchr(p, ','))) 555 *p = '\0'; 556 } 557 } 558 return True; 559} 560 561static void 562FreeMultiDefs(XkbRF_MultiDefsPtr defs) 563{ 564 if (defs->options) _XkbFree(defs->options); 565 if (defs->layout[1]) _XkbFree(defs->layout[1]); 566 if (defs->variant[1]) _XkbFree(defs->variant[1]); 567} 568 569static void 570Apply(char *src, char **dst) 571{ 572 if (src) { 573 if (*src == '+' || *src == '!') { 574 *dst= _Concat(*dst, src); 575 } else { 576 if (*dst == NULL) 577 *dst= _XkbDupString(src); 578 } 579 } 580} 581 582static void 583XkbRF_ApplyRule( XkbRF_RulePtr rule, 584 XkbComponentNamesPtr names) 585{ 586 rule->flags&= ~XkbRF_PendingMatch; /* clear the flag because it's applied */ 587 588 Apply(rule->keycodes, &names->keycodes); 589 Apply(rule->symbols, &names->symbols); 590 Apply(rule->types, &names->types); 591 Apply(rule->compat, &names->compat); 592 Apply(rule->geometry, &names->geometry); 593} 594 595static Bool 596CheckGroup( XkbRF_RulesPtr rules, 597 char * group_name, 598 char * name) 599{ 600 int i; 601 char *p; 602 XkbRF_GroupPtr group; 603 604 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) { 605 if (! strcmp(group->name, group_name)) { 606 break; 607 } 608 } 609 if (i == rules->num_groups) 610 return False; 611 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p)+1) { 612 if (! strcmp(p, name)) { 613 return True; 614 } 615 } 616 return False; 617} 618 619static int 620XkbRF_CheckApplyRule( XkbRF_RulePtr rule, 621 XkbRF_MultiDefsPtr mdefs, 622 XkbComponentNamesPtr names, 623 XkbRF_RulesPtr rules) 624{ 625 Bool pending = False; 626 627 if (rule->model != NULL) { 628 if(mdefs->model == NULL) 629 return 0; 630 if (strcmp(rule->model, "*") == 0) { 631 pending = True; 632 } else { 633 if (rule->model[0] == '$') { 634 if (!CheckGroup(rules, rule->model, mdefs->model)) 635 return 0; 636 } else { 637 if (strcmp(rule->model, mdefs->model) != 0) 638 return 0; 639 } 640 } 641 } 642 if (rule->option != NULL) { 643 if (mdefs->options == NULL) 644 return 0; 645 if ((!MatchOneOf(rule->option,mdefs->options))) 646 return 0; 647 } 648 649 if (rule->layout != NULL) { 650 if(mdefs->layout[rule->layout_num] == NULL || 651 *mdefs->layout[rule->layout_num] == '\0') 652 return 0; 653 if (strcmp(rule->layout, "*") == 0) { 654 pending = True; 655 } else { 656 if (rule->layout[0] == '$') { 657 if (!CheckGroup(rules, rule->layout, 658 mdefs->layout[rule->layout_num])) 659 return 0; 660 } else { 661 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0) 662 return 0; 663 } 664 } 665 } 666 if (rule->variant != NULL) { 667 if (mdefs->variant[rule->variant_num] == NULL || 668 *mdefs->variant[rule->variant_num] == '\0') 669 return 0; 670 if (strcmp(rule->variant, "*") == 0) { 671 pending = True; 672 } else { 673 if (rule->variant[0] == '$') { 674 if (!CheckGroup(rules, rule->variant, 675 mdefs->variant[rule->variant_num])) 676 return 0; 677 } else { 678 if (strcmp(rule->variant, 679 mdefs->variant[rule->variant_num]) != 0) 680 return 0; 681 } 682 } 683 } 684 if (pending) { 685 rule->flags|= XkbRF_PendingMatch; 686 return rule->number; 687 } 688 /* exact match, apply it now */ 689 XkbRF_ApplyRule(rule,names); 690 return rule->number; 691} 692 693static void 694XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules) 695{ 696register int i; 697XkbRF_RulePtr rule; 698 699 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { 700 rule->flags&= ~XkbRF_PendingMatch; 701 } 702} 703 704static void 705XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules,XkbComponentNamesPtr names) 706{ 707int i; 708XkbRF_RulePtr rule; 709 710 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) { 711 if ((rule->flags&XkbRF_PendingMatch)==0) 712 continue; 713 XkbRF_ApplyRule(rule,names); 714 } 715} 716 717static void 718XkbRF_CheckApplyRules( XkbRF_RulesPtr rules, 719 XkbRF_MultiDefsPtr mdefs, 720 XkbComponentNamesPtr names, 721 int flags) 722{ 723int i; 724XkbRF_RulePtr rule; 725int skip; 726 727 for (rule = rules->rules, i=0; i < rules->num_rules; rule++, i++) { 728 if ((rule->flags & flags) != flags) 729 continue; 730 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules); 731 if (skip && !(flags & XkbRF_Option)) { 732 for ( ;(i < rules->num_rules) && (rule->number == skip); 733 rule++, i++); 734 rule--; i--; 735 } 736 } 737} 738 739/***====================================================================***/ 740 741static char * 742XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs) 743{ 744char *str, *outstr, *orig, *var; 745int len, ndx; 746 747 orig= name; 748 str= index(name,'%'); 749 if (str==NULL) 750 return name; 751 len= strlen(name); 752 while (str!=NULL) { 753 char pfx= str[1]; 754 int extra_len= 0; 755 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { 756 extra_len= 1; 757 str++; 758 } 759 else if (pfx=='(') { 760 extra_len= 2; 761 str++; 762 } 763 var = str + 1; 764 str = get_index(var + 1, &ndx); 765 if (ndx == -1) { 766 str = index(str,'%'); 767 continue; 768 } 769 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) 770 len+= strlen(mdefs->layout[ndx])+extra_len; 771 else if ((*var=='m')&&mdefs->model) 772 len+= strlen(mdefs->model)+extra_len; 773 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) 774 len+= strlen(mdefs->variant[ndx])+extra_len; 775 if ((pfx=='(')&&(*str==')')) { 776 str++; 777 } 778 str= index(&str[0],'%'); 779 } 780 name= (char *)_XkbAlloc(len+1); 781 str= orig; 782 outstr= name; 783 while (*str!='\0') { 784 if (str[0]=='%') { 785 char pfx,sfx; 786 str++; 787 pfx= str[0]; 788 sfx= '\0'; 789 if ((pfx=='+')||(pfx=='|')||(pfx=='_')||(pfx=='-')) { 790 str++; 791 } 792 else if (pfx=='(') { 793 sfx= ')'; 794 str++; 795 } 796 else pfx= '\0'; 797 798 var = str; 799 str = get_index(var + 1, &ndx); 800 if (ndx == -1) { 801 continue; 802 } 803 if ((*var=='l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) { 804 if (pfx) *outstr++= pfx; 805 strcpy(outstr,mdefs->layout[ndx]); 806 outstr+= strlen(mdefs->layout[ndx]); 807 if (sfx) *outstr++= sfx; 808 } 809 else if ((*var=='m')&&(mdefs->model)) { 810 if (pfx) *outstr++= pfx; 811 strcpy(outstr,mdefs->model); 812 outstr+= strlen(mdefs->model); 813 if (sfx) *outstr++= sfx; 814 } 815 else if ((*var=='v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) { 816 if (pfx) *outstr++= pfx; 817 strcpy(outstr,mdefs->variant[ndx]); 818 outstr+= strlen(mdefs->variant[ndx]); 819 if (sfx) *outstr++= sfx; 820 } 821 if ((pfx=='(')&&(*str==')')) 822 str++; 823 } 824 else { 825 *outstr++= *str++; 826 } 827 } 828 *outstr++= '\0'; 829 if (orig!=name) 830 _XkbFree(orig); 831 return name; 832} 833 834/***====================================================================***/ 835 836Bool 837XkbRF_GetComponents( XkbRF_RulesPtr rules, 838 XkbRF_VarDefsPtr defs, 839 XkbComponentNamesPtr names) 840{ 841 XkbRF_MultiDefsRec mdefs; 842 843 MakeMultiDefs(&mdefs, defs); 844 845 bzero((char *)names,sizeof(XkbComponentNamesRec)); 846 XkbRF_ClearPartialMatches(rules); 847 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal); 848 XkbRF_ApplyPartialMatches(rules, names); 849 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append); 850 XkbRF_ApplyPartialMatches(rules, names); 851 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option); 852 853 if (names->keycodes) 854 names->keycodes= XkbRF_SubstituteVars(names->keycodes, &mdefs); 855 if (names->symbols) 856 names->symbols= XkbRF_SubstituteVars(names->symbols, &mdefs); 857 if (names->types) 858 names->types= XkbRF_SubstituteVars(names->types, &mdefs); 859 if (names->compat) 860 names->compat= XkbRF_SubstituteVars(names->compat, &mdefs); 861 if (names->geometry) 862 names->geometry= XkbRF_SubstituteVars(names->geometry, &mdefs); 863 if (names->keymap) 864 names->keymap= XkbRF_SubstituteVars(names->keymap, &mdefs); 865 866 FreeMultiDefs(&mdefs); 867 return (names->keycodes && names->symbols && names->types && 868 names->compat && names->geometry ) || names->keymap; 869} 870 871XkbRF_RulePtr 872XkbRF_AddRule(XkbRF_RulesPtr rules) 873{ 874 if (rules->sz_rules<1) { 875 rules->sz_rules= 16; 876 rules->num_rules= 0; 877 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec); 878 } 879 else if (rules->num_rules>=rules->sz_rules) { 880 rules->sz_rules*= 2; 881 rules->rules= _XkbTypedRealloc(rules->rules,rules->sz_rules, 882 XkbRF_RuleRec); 883 } 884 if (!rules->rules) { 885 rules->sz_rules= rules->num_rules= 0; 886 DebugF("Allocation failure in XkbRF_AddRule\n"); 887 return NULL; 888 } 889 bzero((char *)&rules->rules[rules->num_rules],sizeof(XkbRF_RuleRec)); 890 return &rules->rules[rules->num_rules++]; 891} 892 893XkbRF_GroupPtr 894XkbRF_AddGroup(XkbRF_RulesPtr rules) 895{ 896 if (rules->sz_groups<1) { 897 rules->sz_groups= 16; 898 rules->num_groups= 0; 899 rules->groups= _XkbTypedCalloc(rules->sz_groups,XkbRF_GroupRec); 900 } 901 else if (rules->num_groups >= rules->sz_groups) { 902 rules->sz_groups *= 2; 903 rules->groups= _XkbTypedRealloc(rules->groups,rules->sz_groups, 904 XkbRF_GroupRec); 905 } 906 if (!rules->groups) { 907 rules->sz_groups= rules->num_groups= 0; 908 return NULL; 909 } 910 911 bzero((char *)&rules->groups[rules->num_groups],sizeof(XkbRF_GroupRec)); 912 return &rules->groups[rules->num_groups++]; 913} 914 915Bool 916XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules) 917{ 918InputLine line; 919RemapSpec remap; 920XkbRF_RuleRec trule,*rule; 921XkbRF_GroupRec tgroup,*group; 922 923 if (!(rules && file)) 924 return False; 925 bzero((char *)&remap,sizeof(RemapSpec)); 926 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec)); 927 InitInputLine(&line); 928 while (GetInputLine(file,&line,True)) { 929 if (CheckLine(&line,&remap,&trule,&tgroup)) { 930 if (tgroup.number) { 931 if ((group= XkbRF_AddGroup(rules))!=NULL) { 932 *group= tgroup; 933 bzero((char *)&tgroup,sizeof(XkbRF_GroupRec)); 934 } 935 } else { 936 if ((rule= XkbRF_AddRule(rules))!=NULL) { 937 *rule= trule; 938 bzero((char *)&trule,sizeof(XkbRF_RuleRec)); 939 } 940 } 941 } 942 line.num_line= 0; 943 } 944 FreeInputLine(&line); 945 return True; 946} 947 948Bool 949XkbRF_LoadRulesByName(char *base,char *locale,XkbRF_RulesPtr rules) 950{ 951FILE * file; 952char buf[PATH_MAX]; 953Bool ok; 954 955 if ((!base)||(!rules)) 956 return False; 957 if (locale) { 958 if (strlen(base)+strlen(locale)+2 > PATH_MAX) 959 return False; 960 sprintf(buf,"%s-%s", base, locale); 961 } 962 else { 963 if (strlen(base)+1 > PATH_MAX) 964 return False; 965 strcpy(buf,base); 966 } 967 968 file= fopen(buf, "r"); 969 if ((!file)&&(locale)) { /* fallback if locale was specified */ 970 strcpy(buf,base); 971 file= fopen(buf, "r"); 972 } 973 if (!file) 974 return False; 975 ok= XkbRF_LoadRules(file,rules); 976 fclose(file); 977 return ok; 978} 979 980/***====================================================================***/ 981 982#define HEAD_NONE 0 983#define HEAD_MODEL 1 984#define HEAD_LAYOUT 2 985#define HEAD_VARIANT 3 986#define HEAD_OPTION 4 987#define HEAD_EXTRA 5 988 989XkbRF_VarDescPtr 990XkbRF_AddVarDesc(XkbRF_DescribeVarsPtr vars) 991{ 992 if (vars->sz_desc<1) { 993 vars->sz_desc= 16; 994 vars->num_desc= 0; 995 vars->desc= _XkbTypedCalloc(vars->sz_desc,XkbRF_VarDescRec); 996 } 997 else if (vars->num_desc>=vars->sz_desc) { 998 vars->sz_desc*= 2; 999 vars->desc= _XkbTypedRealloc(vars->desc,vars->sz_desc,XkbRF_VarDescRec); 1000 } 1001 if (!vars->desc) { 1002 vars->sz_desc= vars->num_desc= 0; 1003 DebugF("Allocation failure in XkbRF_AddVarDesc\n"); 1004 return NULL; 1005 } 1006 vars->desc[vars->num_desc].name= NULL; 1007 vars->desc[vars->num_desc].desc= NULL; 1008 return &vars->desc[vars->num_desc++]; 1009} 1010 1011XkbRF_VarDescPtr 1012XkbRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars,XkbRF_VarDescPtr from) 1013{ 1014XkbRF_VarDescPtr nd; 1015 1016 if ((nd=XkbRF_AddVarDesc(vars))!=NULL) { 1017 nd->name= _XkbDupString(from->name); 1018 nd->desc= _XkbDupString(from->desc); 1019 } 1020 return nd; 1021} 1022 1023XkbRF_DescribeVarsPtr 1024XkbRF_AddVarToDescribe(XkbRF_RulesPtr rules,char *name) 1025{ 1026 if (rules->sz_extra<1) { 1027 rules->num_extra= 0; 1028 rules->sz_extra= 1; 1029 rules->extra_names= _XkbTypedCalloc(rules->sz_extra,char *); 1030 rules->extra= _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec); 1031 } 1032 else if (rules->num_extra>=rules->sz_extra) { 1033 rules->sz_extra*= 2; 1034 rules->extra_names= _XkbTypedRealloc(rules->extra_names,rules->sz_extra, 1035 char *); 1036 rules->extra=_XkbTypedRealloc(rules->extra, rules->sz_extra, 1037 XkbRF_DescribeVarsRec); 1038 } 1039 if ((!rules->extra_names)||(!rules->extra)) { 1040 DebugF("allocation error in extra parts\n"); 1041 rules->sz_extra= rules->num_extra= 0; 1042 rules->extra_names= NULL; 1043 rules->extra= NULL; 1044 return NULL; 1045 } 1046 rules->extra_names[rules->num_extra]= _XkbDupString(name); 1047 bzero(&rules->extra[rules->num_extra],sizeof(XkbRF_DescribeVarsRec)); 1048 return &rules->extra[rules->num_extra++]; 1049} 1050 1051Bool 1052XkbRF_LoadDescriptions(FILE *file,XkbRF_RulesPtr rules) 1053{ 1054InputLine line; 1055XkbRF_VarDescRec tmp; 1056char *tok; 1057int len,headingtype,extra_ndx = 0; 1058 1059 bzero((char *)&tmp, sizeof(XkbRF_VarDescRec)); 1060 headingtype = HEAD_NONE; 1061 InitInputLine(&line); 1062 for ( ; GetInputLine(file,&line,False); line.num_line= 0) { 1063 if (line.line[0]=='!') { 1064 tok = strtok(&(line.line[1]), " \t"); 1065 if (strcasecmp(tok,"model") == 0) 1066 headingtype = HEAD_MODEL; 1067 else if (strcasecmp(tok,"layout") == 0) 1068 headingtype = HEAD_LAYOUT; 1069 else if (strcasecmp(tok,"variant") == 0) 1070 headingtype = HEAD_VARIANT; 1071 else if (strcasecmp(tok,"option") == 0) 1072 headingtype = HEAD_OPTION; 1073 else { 1074 int i; 1075 headingtype = HEAD_EXTRA; 1076 extra_ndx= -1; 1077 for (i=0;(i<rules->num_extra)&&(extra_ndx<0);i++) { 1078 if (!strcasecmp(tok,rules->extra_names[i])) 1079 extra_ndx= i; 1080 } 1081 if (extra_ndx<0) { 1082 XkbRF_DescribeVarsPtr var; 1083 DebugF("Extra heading \"%s\" encountered\n",tok); 1084 var= XkbRF_AddVarToDescribe(rules,tok); 1085 if (var) 1086 extra_ndx= var-rules->extra; 1087 else headingtype= HEAD_NONE; 1088 } 1089 } 1090 continue; 1091 } 1092 1093 if (headingtype == HEAD_NONE) { 1094 DebugF("Must have a heading before first line of data\n"); 1095 DebugF("Illegal line of data ignored\n"); 1096 continue; 1097 } 1098 1099 len = strlen(line.line); 1100 if ((tmp.name= strtok(line.line, " \t")) == NULL) { 1101 DebugF("Huh? No token on line\n"); 1102 DebugF("Illegal line of data ignored\n"); 1103 continue; 1104 } 1105 if (strlen(tmp.name) == len) { 1106 DebugF("No description found\n"); 1107 DebugF("Illegal line of data ignored\n"); 1108 continue; 1109 } 1110 1111 tok = line.line + strlen(tmp.name) + 1; 1112 while ((*tok!='\n')&&isspace(*tok)) 1113 tok++; 1114 if (*tok == '\0') { 1115 DebugF("No description found\n"); 1116 DebugF("Illegal line of data ignored\n"); 1117 continue; 1118 } 1119 tmp.desc= tok; 1120 switch (headingtype) { 1121 case HEAD_MODEL: 1122 XkbRF_AddVarDescCopy(&rules->models,&tmp); 1123 break; 1124 case HEAD_LAYOUT: 1125 XkbRF_AddVarDescCopy(&rules->layouts,&tmp); 1126 break; 1127 case HEAD_VARIANT: 1128 XkbRF_AddVarDescCopy(&rules->variants,&tmp); 1129 break; 1130 case HEAD_OPTION: 1131 XkbRF_AddVarDescCopy(&rules->options,&tmp); 1132 break; 1133 case HEAD_EXTRA: 1134 XkbRF_AddVarDescCopy(&rules->extra[extra_ndx],&tmp); 1135 break; 1136 } 1137 } 1138 FreeInputLine(&line); 1139 if ((rules->models.num_desc==0) && (rules->layouts.num_desc==0) && 1140 (rules->variants.num_desc==0) && (rules->options.num_desc==0) && 1141 (rules->num_extra==0)) { 1142 return False; 1143 } 1144 return True; 1145} 1146 1147Bool 1148XkbRF_LoadDescriptionsByName(char *base,char *locale,XkbRF_RulesPtr rules) 1149{ 1150FILE * file; 1151char buf[PATH_MAX]; 1152Bool ok; 1153 1154 if ((!base)||(!rules)) 1155 return False; 1156 if (locale) { 1157 if (strlen(base)+strlen(locale)+6 > PATH_MAX) 1158 return False; 1159 sprintf(buf,"%s-%s.lst", base, locale); 1160 } 1161 else { 1162 if (strlen(base)+5 > PATH_MAX) 1163 return False; 1164 sprintf(buf,"%s.lst", base); 1165 } 1166 1167 file= fopen(buf, "r"); 1168 if ((!file)&&(locale)) { /* fallback if locale was specified */ 1169 sprintf(buf,"%s.lst", base); 1170 1171 file= fopen(buf, "r"); 1172 } 1173 if (!file) 1174 return False; 1175 ok= XkbRF_LoadDescriptions(file,rules); 1176 fclose(file); 1177 return ok; 1178} 1179 1180/***====================================================================***/ 1181 1182XkbRF_RulesPtr 1183XkbRF_Load(char *base,char *locale,Bool wantDesc,Bool wantRules) 1184{ 1185XkbRF_RulesPtr rules; 1186 1187 if ((!base)||((!wantDesc)&&(!wantRules))) 1188 return NULL; 1189 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL) 1190 return NULL; 1191 if (wantDesc&&(!XkbRF_LoadDescriptionsByName(base,locale,rules))) { 1192 XkbRF_Free(rules,True); 1193 return NULL; 1194 } 1195 if (wantRules&&(!XkbRF_LoadRulesByName(base,locale,rules))) { 1196 XkbRF_Free(rules,True); 1197 return NULL; 1198 } 1199 return rules; 1200} 1201 1202XkbRF_RulesPtr 1203XkbRF_Create(int szRules,int szExtra) 1204{ 1205XkbRF_RulesPtr rules; 1206 1207 if ((rules=_XkbTypedCalloc(1,XkbRF_RulesRec))==NULL) 1208 return NULL; 1209 if (szRules>0) { 1210 rules->sz_rules= szRules; 1211 rules->rules= _XkbTypedCalloc(rules->sz_rules,XkbRF_RuleRec); 1212 if (!rules->rules) { 1213 _XkbFree(rules); 1214 return NULL; 1215 } 1216 } 1217 if (szExtra>0) { 1218 rules->sz_extra= szExtra; 1219 rules->extra= _XkbTypedCalloc(rules->sz_extra,XkbRF_DescribeVarsRec); 1220 if (!rules->extra) { 1221 if (rules->rules) 1222 _XkbFree(rules->rules); 1223 _XkbFree(rules); 1224 return NULL; 1225 } 1226 } 1227 return rules; 1228} 1229 1230/***====================================================================***/ 1231 1232static void 1233XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var) 1234{ 1235register int i; 1236 1237 for (i=0;i<var->num_desc;i++) { 1238 if (var->desc[i].name) 1239 _XkbFree(var->desc[i].name); 1240 if (var->desc[i].desc) 1241 _XkbFree(var->desc[i].desc); 1242 var->desc[i].name= var->desc[i].desc= NULL; 1243 } 1244 if (var->desc) 1245 _XkbFree(var->desc); 1246 var->desc= NULL; 1247 return; 1248} 1249 1250void 1251XkbRF_Free(XkbRF_RulesPtr rules,Bool freeRules) 1252{ 1253int i; 1254XkbRF_RulePtr rule; 1255XkbRF_GroupPtr group; 1256 1257 if (!rules) 1258 return; 1259 XkbRF_ClearVarDescriptions(&rules->models); 1260 XkbRF_ClearVarDescriptions(&rules->layouts); 1261 XkbRF_ClearVarDescriptions(&rules->variants); 1262 XkbRF_ClearVarDescriptions(&rules->options); 1263 if (rules->extra) { 1264 for (i = 0; i < rules->num_extra; i++) { 1265 XkbRF_ClearVarDescriptions(&rules->extra[i]); 1266 } 1267 _XkbFree(rules->extra); 1268 rules->num_extra= rules->sz_extra= 0; 1269 rules->extra= NULL; 1270 } 1271 if (rules->rules) { 1272 for (i=0,rule=rules->rules;i<rules->num_rules;i++,rule++) { 1273 if (rule->model) _XkbFree(rule->model); 1274 if (rule->layout) _XkbFree(rule->layout); 1275 if (rule->variant) _XkbFree(rule->variant); 1276 if (rule->option) _XkbFree(rule->option); 1277 if (rule->keycodes) _XkbFree(rule->keycodes); 1278 if (rule->symbols) _XkbFree(rule->symbols); 1279 if (rule->types) _XkbFree(rule->types); 1280 if (rule->compat) _XkbFree(rule->compat); 1281 if (rule->geometry) _XkbFree(rule->geometry); 1282 bzero((char *)rule,sizeof(XkbRF_RuleRec)); 1283 } 1284 _XkbFree(rules->rules); 1285 rules->num_rules= rules->sz_rules= 0; 1286 rules->rules= NULL; 1287 } 1288 1289 if (rules->groups) { 1290 for (i=0, group=rules->groups;i<rules->num_groups;i++,group++) { 1291 if (group->name) _XkbFree(group->name); 1292 if (group->words) _XkbFree(group->words); 1293 } 1294 _XkbFree(rules->groups); 1295 rules->num_groups= 0; 1296 rules->groups= NULL; 1297 } 1298 if (freeRules) 1299 _XkbFree(rules); 1300 return; 1301} 1302