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