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 #elif defined(HAVE_CONFIG_H) 30 #include <config.h> 31 #endif 32 33 #include <stdio.h> 34 #include <ctype.h> 35 #include <stdlib.h> 36 37 #define X_INCLUDE_STRING_H 38 #define XOS_USE_NO_LOCKING 39 #include <X11/Xos_r.h> 40 41 42 #include <X11/Xproto.h> 43 #include <X11/Xlib.h> 44 #include <X11/Xos.h> 45 #include <X11/Xfuncs.h> 46 #include <X11/Xatom.h> 47 #include <X11/keysym.h> 48 #include <X11/XKBlib.h> 49 #include <X11/extensions/XKBgeom.h> 50 #include "XKMformat.h" 51 #include "XKBfileInt.h" 52 #include "XKBrules.h" 53 54 #ifdef O_CLOEXEC 55 #define FOPEN_CLOEXEC "e" 56 #else 57 #define FOPEN_CLOEXEC "" 58 #endif 59 60 #ifdef DEBUG 61 #define PR_DEBUG(s) fprintf(stderr,s) 62 #define PR_DEBUG1(s,a) fprintf(stderr,s,a) 63 #define PR_DEBUG2(s,a,b) fprintf(stderr,s,a,b) 64 #else 65 #define PR_DEBUG(s) 66 #define PR_DEBUG1(s,a) 67 #define PR_DEBUG2(s,a,b) 68 #endif 69 70 /***====================================================================***/ 71 72 #define DFLT_LINE_SIZE 128 73 74 typedef struct { 75 int line_num; 76 int sz_line; 77 int num_line; 78 char buf[DFLT_LINE_SIZE]; 79 char * line; 80 } InputLine; 81 82 static void 83 InitInputLine(InputLine *line) 84 { 85 line->line_num = 1; 86 line->num_line = 0; 87 line->sz_line = DFLT_LINE_SIZE; 88 line->line = line->buf; 89 return; 90 } 91 92 static void 93 FreeInputLine(InputLine *line) 94 { 95 if (line->line != line->buf) 96 _XkbFree(line->line); 97 line->line_num = 1; 98 line->num_line = 0; 99 line->sz_line = DFLT_LINE_SIZE; 100 line->line = line->buf; 101 return; 102 } 103 104 static int 105 InputLineAddChar(InputLine *line, int ch) 106 { 107 if (line->num_line >= line->sz_line) { 108 if (line->line == line->buf) { 109 line->line = _XkbAlloc(line->sz_line * 2); 110 memcpy(line->line, line->buf, line->sz_line); 111 } 112 else { 113 line->line = _XkbRealloc(line->line, line->sz_line * 2); 114 } 115 line->sz_line *= 2; 116 } 117 line->line[line->num_line++] = ch; 118 return ch; 119 } 120 121 #define ADD_CHAR(l,c) ((l)->num_line<(l)->sz_line?\ 122 (int)((l)->line[(l)->num_line++]= (c)):\ 123 InputLineAddChar(l,c)) 124 125 #ifdef HAVE_UNLOCKED_STDIO 126 #undef getc 127 #define getc(x) getc_unlocked(x) 128 #else 129 #define flockfile(x) do {} while (0) 130 #define funlockfile(x) do {} while (0) 131 #endif 132 133 static Bool 134 GetInputLine(FILE *file, InputLine *line, Bool checkbang) 135 { 136 int ch; 137 Bool endOfFile, spacePending, slashPending, inComment; 138 139 endOfFile = False; 140 flockfile(file); 141 while ((!endOfFile) && (line->num_line == 0)) { 142 spacePending = slashPending = inComment = False; 143 while (((ch = getc(file)) != '\n') && (ch != EOF)) { 144 if (ch == '\\') { 145 if ((ch = getc(file)) == EOF) 146 break; 147 if (ch == '\n') { 148 inComment = False; 149 ch = ' '; 150 line->line_num++; 151 } 152 } 153 if (inComment) 154 continue; 155 if (ch == '/') { 156 if (slashPending) { 157 inComment = True; 158 slashPending = False; 159 } 160 else { 161 slashPending = True; 162 } 163 continue; 164 } 165 else if (slashPending) { 166 if (spacePending) { 167 ADD_CHAR(line, ' '); 168 spacePending = False; 169 } 170 ADD_CHAR(line, '/'); 171 slashPending = False; 172 } 173 if (isspace(ch)) { 174 while (isspace(ch) && (ch != '\n') && (ch != EOF)) { 175 ch = getc(file); 176 } 177 if (ch == EOF) 178 break; 179 if ((ch != '\n') && (line->num_line > 0)) 180 spacePending = True; 181 ungetc(ch, file); 182 } 183 else { 184 if (spacePending) { 185 ADD_CHAR(line, ' '); 186 spacePending = False; 187 } 188 if (checkbang && ch == '!') { 189 if (line->num_line != 0) { 190 PR_DEBUG("The '!' legal only at start of line\n"); 191 PR_DEBUG("Line containing '!' ignored\n"); 192 line->num_line = 0; 193 inComment = 0; 194 break; 195 } 196 197 } 198 ADD_CHAR(line, ch); 199 } 200 } 201 if (ch == EOF) 202 endOfFile = True; 203 /* else line->num_line++;*/ 204 } 205 funlockfile(file); 206 if ((line->num_line == 0) && (endOfFile)) 207 return False; 208 ADD_CHAR(line, '\0'); 209 return True; 210 } 211 212 /***====================================================================***/ 213 214 #define MODEL 0 215 #define LAYOUT 1 216 #define VARIANT 2 217 #define OPTION 3 218 #define KEYCODES 4 219 #define SYMBOLS 5 220 #define TYPES 6 221 #define COMPAT 7 222 #define GEOMETRY 8 223 #define KEYMAP 9 224 #define MAX_WORDS 10 225 226 #define PART_MASK 0x000F 227 #define COMPONENT_MASK 0x03F0 228 229 static const char *cname[MAX_WORDS] = { 230 "model", "layout", "variant", "option", 231 "keycodes", "symbols", "types", "compat", "geometry", "keymap" 232 }; 233 234 typedef struct _RemapSpec { 235 int number; 236 int num_remap; 237 struct { 238 int word; 239 int index; 240 } remap[MAX_WORDS]; 241 } RemapSpec; 242 243 typedef struct _FileSpec { 244 char *name[MAX_WORDS]; 245 struct _FileSpec *pending; 246 } FileSpec; 247 248 typedef struct { 249 char *model; 250 char *layout[XkbNumKbdGroups + 1]; 251 char *variant[XkbNumKbdGroups + 1]; 252 char *options; 253 } XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr; 254 255 #define NDX_BUFF_SIZE 4 256 257 /***====================================================================***/ 258 259 static char * 260 get_index(char *str, int *ndx) 261 { 262 char ndx_buf[NDX_BUFF_SIZE]; 263 264 char *end; 265 266 if (*str != '[') { 267 *ndx = 0; 268 return str; 269 } 270 str++; 271 end = strchr(str, ']'); 272 if (end == NULL) { 273 *ndx = -1; 274 return str - 1; 275 } 276 if ((end - str) >= NDX_BUFF_SIZE) { 277 *ndx = -1; 278 return end + 1; 279 } 280 strncpy(ndx_buf, str, end - str); 281 ndx_buf[end - str] = '\0'; 282 *ndx = atoi(ndx_buf); 283 return end + 1; 284 } 285 286 static void 287 SetUpRemap(InputLine *line, RemapSpec *remap) 288 { 289 char *tok, *str; 290 unsigned present, l_ndx_present, v_ndx_present; 291 register int i; 292 int len, ndx; 293 _Xstrtokparams strtok_buf; 294 295 #ifdef DEBUG 296 Bool found; 297 #endif 298 299 l_ndx_present = v_ndx_present = present = 0; 300 str = &line->line[1]; 301 len = remap->number; 302 memset(remap, 0, sizeof(RemapSpec)); 303 remap->number = len; 304 while ((tok = _XStrtok(str, " ", strtok_buf)) != NULL) { 305 #ifdef DEBUG 306 found = False; 307 #endif 308 str = NULL; 309 if (strcmp(tok, "=") == 0) 310 continue; 311 for (i = 0; i < MAX_WORDS; i++) { 312 len = strlen(cname[i]); 313 if (strncmp(cname[i], tok, len) == 0) { 314 if (strlen(tok) > len) { 315 char *end = get_index(tok + len, &ndx); 316 317 if ((i != LAYOUT && i != VARIANT) || 318 *end != '\0' || ndx == -1) 319 break; 320 if (ndx < 1 || ndx > XkbNumKbdGroups) { 321 PR_DEBUG2("Illegal %s index: %d\n", cname[i], ndx); 322 PR_DEBUG1("Index must be in range 1..%d\n", 323 XkbNumKbdGroups); 324 break; 325 } 326 } 327 else { 328 ndx = 0; 329 } 330 #ifdef DEBUG 331 found = True; 332 #endif 333 if (present & (1 << i)) { 334 if ((i == LAYOUT && l_ndx_present & (1 << ndx)) || 335 (i == VARIANT && v_ndx_present & (1 << ndx))) { 336 PR_DEBUG1("Component \"%s\" listed twice\n", tok); 337 PR_DEBUG("Second definition ignored\n"); 338 break; 339 } 340 } 341 present |= (1 << i); 342 if (i == LAYOUT) 343 l_ndx_present |= 1 << ndx; 344 if (i == VARIANT) 345 v_ndx_present |= 1 << ndx; 346 remap->remap[remap->num_remap].word = i; 347 remap->remap[remap->num_remap++].index = ndx; 348 break; 349 } 350 } 351 #ifdef DEBUG 352 if (!found) { 353 fprintf(stderr, "Unknown component \"%s\" ignored\n", tok); 354 } 355 #endif 356 } 357 if ((present & PART_MASK) == 0) { 358 #ifdef DEBUG 359 unsigned mask = PART_MASK; 360 361 fprintf(stderr, "Mapping needs at least one of "); 362 for (i = 0; (i < MAX_WORDS); i++) { 363 if ((1L << i) & mask) { 364 mask &= ~(1L << i); 365 if (mask) 366 fprintf(stderr, "\"%s,\" ", cname[i]); 367 else 368 fprintf(stderr, "or \"%s\"\n", cname[i]); 369 } 370 } 371 fprintf(stderr, "Illegal mapping ignored\n"); 372 #endif 373 remap->num_remap = 0; 374 return; 375 } 376 if ((present & COMPONENT_MASK) == 0) { 377 PR_DEBUG("Mapping needs at least one component\n"); 378 PR_DEBUG("Illegal mapping ignored\n"); 379 remap->num_remap = 0; 380 return; 381 } 382 if (((present & COMPONENT_MASK) & (1 << KEYMAP)) && 383 ((present & COMPONENT_MASK) != (1 << KEYMAP))) { 384 PR_DEBUG("Keymap cannot appear with other components\n"); 385 PR_DEBUG("Illegal mapping ignored\n"); 386 remap->num_remap = 0; 387 return; 388 } 389 remap->number++; 390 return; 391 } 392 393 static Bool 394 MatchOneOf(char *wanted, char *vals_defined) 395 { 396 char *str, *next; 397 int want_len = strlen(wanted); 398 399 for (str = vals_defined, next = NULL; str != NULL; str = next) { 400 int len; 401 402 next = strchr(str, ','); 403 if (next) { 404 len = next - str; 405 next++; 406 } 407 else { 408 len = strlen(str); 409 } 410 if ((len == want_len) && (strncmp(wanted, str, len) == 0)) 411 return True; 412 } 413 return False; 414 } 415 416 /***====================================================================***/ 417 418 static Bool 419 CheckLine(InputLine * line, 420 RemapSpec * remap, 421 XkbRF_RulePtr rule, 422 XkbRF_GroupPtr group) 423 { 424 char *str, *tok; 425 register int nread, i; 426 FileSpec tmp; 427 _Xstrtokparams strtok_buf; 428 Bool append = False; 429 430 if (line->line[0] == '!') { 431 if (line->line[1] == '$' || 432 (line->line[1] == ' ' && line->line[2] == '$')) { 433 char *gname = strchr(line->line, '$'); 434 char *words = strchr(gname, ' '); 435 436 if (!words) 437 return False; 438 *words++ = '\0'; 439 for (; *words; words++) { 440 if (*words != '=' && *words != ' ') 441 break; 442 } 443 if (*words == '\0') 444 return False; 445 group->name = _XkbDupString(gname); 446 group->words = _XkbDupString(words); 447 for (i = 1, words = group->words; *words; words++) { 448 if (*words == ' ') { 449 *words++ = '\0'; 450 i++; 451 } 452 } 453 group->number = i; 454 return True; 455 } 456 else { 457 SetUpRemap(line, remap); 458 return False; 459 } 460 } 461 462 if (remap->num_remap == 0) { 463 PR_DEBUG("Must have a mapping before first line of data\n"); 464 PR_DEBUG("Illegal line of data ignored\n"); 465 return False; 466 } 467 memset(&tmp, 0, sizeof(FileSpec)); 468 str = line->line; 469 for (nread = 0; (tok = _XStrtok(str, " ", strtok_buf)) != NULL; nread++) { 470 str = NULL; 471 if (strcmp(tok, "=") == 0) { 472 nread--; 473 continue; 474 } 475 if (nread > remap->num_remap) { 476 PR_DEBUG("Too many words on a line\n"); 477 PR_DEBUG1("Extra word \"%s\" ignored\n", tok); 478 continue; 479 } 480 tmp.name[remap->remap[nread].word] = tok; 481 if (*tok == '+' || *tok == '|') 482 append = True; 483 } 484 if (nread < remap->num_remap) { 485 PR_DEBUG1("Too few words on a line: %s\n", line->line); 486 PR_DEBUG("line ignored\n"); 487 return False; 488 } 489 490 rule->flags = 0; 491 rule->number = remap->number; 492 if (tmp.name[OPTION]) 493 rule->flags |= XkbRF_Option; 494 else if (append) 495 rule->flags |= XkbRF_Append; 496 else 497 rule->flags |= XkbRF_Normal; 498 rule->model = _XkbDupString(tmp.name[MODEL]); 499 rule->layout = _XkbDupString(tmp.name[LAYOUT]); 500 rule->variant = _XkbDupString(tmp.name[VARIANT]); 501 rule->option = _XkbDupString(tmp.name[OPTION]); 502 503 rule->keycodes = _XkbDupString(tmp.name[KEYCODES]); 504 rule->symbols = _XkbDupString(tmp.name[SYMBOLS]); 505 rule->types = _XkbDupString(tmp.name[TYPES]); 506 rule->compat = _XkbDupString(tmp.name[COMPAT]); 507 rule->geometry = _XkbDupString(tmp.name[GEOMETRY]); 508 rule->keymap = _XkbDupString(tmp.name[KEYMAP]); 509 510 rule->layout_num = rule->variant_num = 0; 511 for (i = 0; i < nread; i++) { 512 if (remap->remap[i].index) { 513 if (remap->remap[i].word == LAYOUT) 514 rule->layout_num = remap->remap[i].index; 515 if (remap->remap[i].word == VARIANT) 516 rule->variant_num = remap->remap[i].index; 517 } 518 } 519 return True; 520 } 521 522 static char * 523 _Concat(char *str1, char *str2) 524 { 525 int len; 526 527 if ((!str1) || (!str2)) 528 return str1; 529 len = strlen(str1) + strlen(str2) + 1; 530 str1 = _XkbTypedReallocF(str1, len, char); 531 if (str1) 532 strcat(str1, str2); 533 return str1; 534 } 535 536 static void 537 squeeze_spaces(char *p1) 538 { 539 char *p2; 540 541 for (p2 = p1; *p2; p2++) { 542 *p1 = *p2; 543 if (*p1 != ' ') 544 p1++; 545 } 546 *p1 = '\0'; 547 } 548 549 static Bool 550 MakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs) 551 { 552 553 memset(mdefs, 0, sizeof(XkbRF_MultiDefsRec)); 554 mdefs->model = defs->model; 555 mdefs->options = _XkbDupString(defs->options); 556 if (mdefs->options) 557 squeeze_spaces(mdefs->options); 558 559 if (defs->layout) { 560 if (!strchr(defs->layout, ',')) { 561 mdefs->layout[0] = defs->layout; 562 } 563 else { 564 char *p; 565 566 int i; 567 568 mdefs->layout[1] = _XkbDupString(defs->layout); 569 if (mdefs->layout[1] == NULL) 570 return False; 571 squeeze_spaces(mdefs->layout[1]); 572 p = mdefs->layout[1]; 573 for (i = 2; i <= XkbNumKbdGroups; i++) { 574 if ((p = strchr(p, ','))) { 575 *p++ = '\0'; 576 mdefs->layout[i] = p; 577 } 578 else { 579 break; 580 } 581 } 582 if (p && (p = strchr(p, ','))) 583 *p = '\0'; 584 } 585 } 586 587 if (defs->variant) { 588 if (!strchr(defs->variant, ',')) { 589 mdefs->variant[0] = defs->variant; 590 } 591 else { 592 char *p; 593 594 int i; 595 596 mdefs->variant[1] = _XkbDupString(defs->variant); 597 if (mdefs->variant[1] == NULL) 598 return False; 599 squeeze_spaces(mdefs->variant[1]); 600 p = mdefs->variant[1]; 601 for (i = 2; i <= XkbNumKbdGroups; i++) { 602 if ((p = strchr(p, ','))) { 603 *p++ = '\0'; 604 mdefs->variant[i] = p; 605 } 606 else { 607 break; 608 } 609 } 610 if (p && (p = strchr(p, ','))) 611 *p = '\0'; 612 } 613 } 614 return True; 615 } 616 617 static void 618 FreeMultiDefs(XkbRF_MultiDefsPtr defs) 619 { 620 if (defs->options) 621 _XkbFree(defs->options); 622 if (defs->layout[1]) 623 _XkbFree(defs->layout[1]); 624 if (defs->variant[1]) 625 _XkbFree(defs->variant[1]); 626 } 627 628 static void 629 Apply(char *src, char **dst) 630 { 631 if (src) { 632 if (*src == '+' || *src == '|') { 633 *dst = _Concat(*dst, src); 634 } 635 else { 636 if (*dst == NULL) 637 *dst = _XkbDupString(src); 638 } 639 } 640 } 641 642 static void 643 XkbRF_ApplyRule(XkbRF_RulePtr rule, XkbComponentNamesPtr names) 644 { 645 rule->flags &= ~XkbRF_PendingMatch; /* clear the flag because it's applied */ 646 647 Apply(rule->keycodes, &names->keycodes); 648 Apply(rule->symbols, &names->symbols); 649 Apply(rule->types, &names->types); 650 Apply(rule->compat, &names->compat); 651 Apply(rule->geometry, &names->geometry); 652 Apply(rule->keymap, &names->keymap); 653 } 654 655 static Bool 656 CheckGroup(XkbRF_RulesPtr rules, char *group_name, char *name) 657 { 658 int i; 659 char *p; 660 XkbRF_GroupPtr group; 661 662 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) { 663 if (!strcmp(group->name, group_name)) { 664 break; 665 } 666 } 667 if (i == rules->num_groups) 668 return False; 669 for (i = 0, p = group->words; i < group->number; i++, p += strlen(p) + 1) { 670 if (!strcmp(p, name)) { 671 return True; 672 } 673 } 674 return False; 675 } 676 677 static int 678 XkbRF_CheckApplyRule(XkbRF_RulePtr rule, 679 XkbRF_MultiDefsPtr mdefs, 680 XkbComponentNamesPtr names, 681 XkbRF_RulesPtr rules) 682 { 683 Bool pending = False; 684 685 if (rule->model != NULL) { 686 if (mdefs->model == NULL) 687 return 0; 688 if (strcmp(rule->model, "*") == 0) { 689 pending = True; 690 } 691 else { 692 if (rule->model[0] == '$') { 693 if (!CheckGroup(rules, rule->model, mdefs->model)) 694 return 0; 695 } 696 else { 697 if (strcmp(rule->model, mdefs->model) != 0) 698 return 0; 699 } 700 } 701 } 702 if (rule->option != NULL) { 703 if (mdefs->options == NULL) 704 return 0; 705 if ((!MatchOneOf(rule->option, mdefs->options))) 706 return 0; 707 } 708 709 if (rule->layout != NULL) { 710 if (mdefs->layout[rule->layout_num] == NULL || 711 *mdefs->layout[rule->layout_num] == '\0') 712 return 0; 713 if (strcmp(rule->layout, "*") == 0) { 714 pending = True; 715 } 716 else { 717 if (rule->layout[0] == '$') { 718 if (!CheckGroup(rules, rule->layout, 719 mdefs->layout[rule->layout_num])) 720 return 0; 721 } 722 else { 723 if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0) 724 return 0; 725 } 726 } 727 } 728 if (rule->variant != NULL) { 729 if (mdefs->variant[rule->variant_num] == NULL || 730 *mdefs->variant[rule->variant_num] == '\0') 731 return 0; 732 if (strcmp(rule->variant, "*") == 0) { 733 pending = True; 734 } 735 else { 736 if (rule->variant[0] == '$') { 737 if (!CheckGroup(rules, rule->variant, 738 mdefs->variant[rule->variant_num])) 739 return 0; 740 } 741 else { 742 if (strcmp(rule->variant, 743 mdefs->variant[rule->variant_num]) != 0) 744 return 0; 745 } 746 } 747 } 748 if (pending) { 749 rule->flags |= XkbRF_PendingMatch; 750 return rule->number; 751 } 752 /* exact match, apply it now */ 753 XkbRF_ApplyRule(rule, names); 754 return rule->number; 755 } 756 757 static void 758 XkbRF_ClearPartialMatches(XkbRF_RulesPtr rules) 759 { 760 register int i; 761 XkbRF_RulePtr rule; 762 763 for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) { 764 rule->flags &= ~XkbRF_PendingMatch; 765 } 766 } 767 768 static void 769 XkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules, XkbComponentNamesPtr names) 770 { 771 int i; 772 XkbRF_RulePtr rule; 773 774 for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) { 775 if ((rule->flags & XkbRF_PendingMatch) == 0) 776 continue; 777 XkbRF_ApplyRule(rule, names); 778 } 779 } 780 781 static void 782 XkbRF_CheckApplyRules(XkbRF_RulesPtr rules, 783 XkbRF_MultiDefsPtr mdefs, 784 XkbComponentNamesPtr names, 785 int flags) 786 { 787 int i; 788 XkbRF_RulePtr rule; 789 int skip; 790 791 for (rule = rules->rules, i = 0; i < rules->num_rules; rule++, i++) { 792 if ((rule->flags & flags) != flags) 793 continue; 794 skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules); 795 if (skip && !(flags & XkbRF_Option)) { 796 for (; (i < rules->num_rules) && (rule->number == skip); 797 rule++, i++); 798 rule--; 799 i--; 800 } 801 } 802 } 803 804 /***====================================================================***/ 805 806 static char * 807 XkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs) 808 { 809 char *str, *outstr, *orig, *var; 810 int len, ndx; 811 812 orig = name; 813 str = index(name, '%'); 814 if (str == NULL) 815 return name; 816 len = strlen(name); 817 while (str != NULL) { 818 char pfx = str[1]; 819 int extra_len = 0; 820 821 if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) { 822 extra_len = 1; 823 str++; 824 } 825 else if (pfx == '(') { 826 extra_len = 2; 827 str++; 828 } 829 var = str + 1; 830 str = get_index(var + 1, &ndx); 831 if (ndx == -1) { 832 str = index(str, '%'); 833 continue; 834 } 835 if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) 836 len += strlen(mdefs->layout[ndx]) + extra_len; 837 else if ((*var == 'm') && mdefs->model) 838 len += strlen(mdefs->model) + extra_len; 839 else if ((*var == 'v') && mdefs->variant[ndx] && *mdefs->variant[ndx]) 840 len += strlen(mdefs->variant[ndx]) + extra_len; 841 if ((pfx == '(') && (*str == ')')) { 842 str++; 843 } 844 str = index(&str[0], '%'); 845 } 846 name = (char *) _XkbAlloc(len + 1); 847 str = orig; 848 outstr = name; 849 while (*str != '\0') { 850 if (str[0] == '%') { 851 char pfx, sfx; 852 853 str++; 854 pfx = str[0]; 855 sfx = '\0'; 856 if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) { 857 str++; 858 } 859 else if (pfx == '(') { 860 sfx = ')'; 861 str++; 862 } 863 else 864 pfx = '\0'; 865 866 var = str; 867 str = get_index(var + 1, &ndx); 868 if (ndx == -1) { 869 continue; 870 } 871 if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) { 872 if (pfx) 873 *outstr++ = pfx; 874 strcpy(outstr, mdefs->layout[ndx]); 875 outstr += strlen(mdefs->layout[ndx]); 876 if (sfx) 877 *outstr++ = sfx; 878 } 879 else if ((*var == 'm') && (mdefs->model)) { 880 if (pfx) 881 *outstr++ = pfx; 882 strcpy(outstr, mdefs->model); 883 outstr += strlen(mdefs->model); 884 if (sfx) 885 *outstr++ = sfx; 886 } 887 else if ((*var == 'v') && mdefs->variant[ndx] && 888 *mdefs->variant[ndx]) { 889 if (pfx) 890 *outstr++ = pfx; 891 strcpy(outstr, mdefs->variant[ndx]); 892 outstr += strlen(mdefs->variant[ndx]); 893 if (sfx) 894 *outstr++ = sfx; 895 } 896 if ((pfx == '(') && (*str == ')')) 897 str++; 898 } 899 else { 900 *outstr++ = *str++; 901 } 902 } 903 *outstr++ = '\0'; 904 if (orig != name) 905 _XkbFree(orig); 906 return name; 907 } 908 909 /***====================================================================***/ 910 911 Bool 912 XkbRF_GetComponents(XkbRF_RulesPtr rules, 913 XkbRF_VarDefsPtr defs, 914 XkbComponentNamesPtr names) 915 { 916 XkbRF_MultiDefsRec mdefs; 917 918 MakeMultiDefs(&mdefs, defs); 919 920 memset(names, 0, sizeof(XkbComponentNamesRec)); 921 XkbRF_ClearPartialMatches(rules); 922 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal); 923 XkbRF_ApplyPartialMatches(rules, names); 924 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append); 925 XkbRF_ApplyPartialMatches(rules, names); 926 XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option); 927 XkbRF_ApplyPartialMatches(rules, names); 928 929 if (names->keycodes) 930 names->keycodes = XkbRF_SubstituteVars(names->keycodes, &mdefs); 931 if (names->symbols) 932 names->symbols = XkbRF_SubstituteVars(names->symbols, &mdefs); 933 if (names->types) 934 names->types = XkbRF_SubstituteVars(names->types, &mdefs); 935 if (names->compat) 936 names->compat = XkbRF_SubstituteVars(names->compat, &mdefs); 937 if (names->geometry) 938 names->geometry = XkbRF_SubstituteVars(names->geometry, &mdefs); 939 if (names->keymap) 940 names->keymap = XkbRF_SubstituteVars(names->keymap, &mdefs); 941 942 FreeMultiDefs(&mdefs); 943 return (names->keycodes && names->symbols && names->types && 944 names->compat && names->geometry) || names->keymap; 945 } 946 947 XkbRF_RulePtr 948 XkbRF_AddRule(XkbRF_RulesPtr rules) 949 { 950 if (rules->sz_rules < 1) { 951 rules->sz_rules = 16; 952 rules->num_rules = 0; 953 rules->rules = _XkbTypedCalloc(rules->sz_rules, XkbRF_RuleRec); 954 } 955 else if (rules->num_rules >= rules->sz_rules) { 956 rules->sz_rules *= 2; 957 rules->rules = _XkbTypedReallocF(rules->rules, rules->sz_rules, 958 XkbRF_RuleRec); 959 } 960 if (!rules->rules) { 961 rules->sz_rules = rules->num_rules = 0; 962 #ifdef DEBUG 963 fprintf(stderr, "Allocation failure in XkbRF_AddRule\n"); 964 #endif 965 return NULL; 966 } 967 memset(&rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec)); 968 return &rules->rules[rules->num_rules++]; 969 } 970 971 XkbRF_GroupPtr 972 XkbRF_AddGroup(XkbRF_RulesPtr rules) 973 { 974 if (rules->sz_groups < 1) { 975 rules->sz_groups = 16; 976 rules->num_groups = 0; 977 rules->groups = _XkbTypedCalloc(rules->sz_groups, XkbRF_GroupRec); 978 } 979 else if (rules->num_groups >= rules->sz_groups) { 980 rules->sz_groups *= 2; 981 rules->groups = _XkbTypedReallocF(rules->groups, rules->sz_groups, 982 XkbRF_GroupRec); 983 } 984 if (!rules->groups) { 985 rules->sz_groups = rules->num_groups = 0; 986 return NULL; 987 } 988 989 memset(&rules->groups[rules->num_groups], 0, sizeof(XkbRF_GroupRec)); 990 return &rules->groups[rules->num_groups++]; 991 } 992 993 Bool 994 XkbRF_LoadRules(FILE *file, XkbRF_RulesPtr rules) 995 { 996 InputLine line; 997 RemapSpec remap; 998 XkbRF_RuleRec trule, *rule; 999 XkbRF_GroupRec tgroup, *group; 1000 1001 if (!(rules && file)) 1002 return False; 1003 memset(&remap, 0, sizeof(RemapSpec)); 1004 memset(&tgroup, 0, sizeof(XkbRF_GroupRec)); 1005 InitInputLine(&line); 1006 while (GetInputLine(file, &line, True)) { 1007 if (CheckLine(&line, &remap, &trule, &tgroup)) { 1008 if (tgroup.number) { 1009 if ((group = XkbRF_AddGroup(rules)) != NULL) { 1010 *group = tgroup; 1011 memset(&tgroup, 0, sizeof(XkbRF_GroupRec)); 1012 } 1013 } 1014 else { 1015 if ((rule = XkbRF_AddRule(rules)) != NULL) { 1016 *rule = trule; 1017 memset(&trule, 0, sizeof(XkbRF_RuleRec)); 1018 } 1019 } 1020 } 1021 line.num_line = 0; 1022 } 1023 FreeInputLine(&line); 1024 return True; 1025 } 1026 1027 Bool 1028 XkbRF_LoadRulesByName(char *base, char *locale, XkbRF_RulesPtr rules) 1029 { 1030 FILE *file; 1031 char buf[PATH_MAX]; 1032 Bool ok; 1033 1034 if ((!base) || (!rules)) 1035 return False; 1036 if (locale) { 1037 if (snprintf(buf, sizeof(buf), "%s-%s", base, locale) >= (int) sizeof(buf)) 1038 return False; 1039 } 1040 else { 1041 if (strlen(base) + 1 > PATH_MAX) 1042 return False; 1043 strcpy(buf, base); 1044 } 1045 1046 file = fopen(buf, "r" FOPEN_CLOEXEC); 1047 if ((!file) && (locale)) { /* fallback if locale was specified */ 1048 strcpy(buf, base); 1049 file = fopen(buf, "r" FOPEN_CLOEXEC); 1050 } 1051 if (!file) 1052 return False; 1053 ok = XkbRF_LoadRules(file, rules); 1054 fclose(file); 1055 return ok; 1056 } 1057 1058 /***====================================================================***/ 1059 1060 #define HEAD_NONE 0 1061 #define HEAD_MODEL 1 1062 #define HEAD_LAYOUT 2 1063 #define HEAD_VARIANT 3 1064 #define HEAD_OPTION 4 1065 #define HEAD_EXTRA 5 1066 1067 XkbRF_VarDescPtr 1068 XkbRF_AddVarDesc(XkbRF_DescribeVarsPtr vars) 1069 { 1070 if (vars->sz_desc < 1) { 1071 vars->sz_desc = 16; 1072 vars->num_desc = 0; 1073 vars->desc = _XkbTypedCalloc(vars->sz_desc, XkbRF_VarDescRec); 1074 } 1075 else if (vars->num_desc >= vars->sz_desc) { 1076 vars->sz_desc *= 2; 1077 vars->desc = 1078 _XkbTypedReallocF(vars->desc, vars->sz_desc, XkbRF_VarDescRec); 1079 } 1080 if (!vars->desc) { 1081 vars->sz_desc = vars->num_desc = 0; 1082 PR_DEBUG("Allocation failure in XkbRF_AddVarDesc\n"); 1083 return NULL; 1084 } 1085 vars->desc[vars->num_desc].name = NULL; 1086 vars->desc[vars->num_desc].desc = NULL; 1087 return &vars->desc[vars->num_desc++]; 1088 } 1089 1090 XkbRF_VarDescPtr 1091 XkbRF_AddVarDescCopy(XkbRF_DescribeVarsPtr vars, XkbRF_VarDescPtr from) 1092 { 1093 XkbRF_VarDescPtr nd; 1094 1095 if ((nd = XkbRF_AddVarDesc(vars)) != NULL) { 1096 nd->name = _XkbDupString(from->name); 1097 nd->desc = _XkbDupString(from->desc); 1098 } 1099 return nd; 1100 } 1101 1102 XkbRF_DescribeVarsPtr 1103 XkbRF_AddVarToDescribe(XkbRF_RulesPtr rules, char *name) 1104 { 1105 if (rules->sz_extra < 1) { 1106 rules->num_extra = 0; 1107 rules->sz_extra = 1; 1108 rules->extra_names = _XkbTypedCalloc(rules->sz_extra, char *); 1109 1110 rules->extra = _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec); 1111 } 1112 else if (rules->num_extra >= rules->sz_extra) { 1113 rules->sz_extra *= 2; 1114 rules->extra_names = 1115 _XkbTypedReallocF(rules->extra_names, rules->sz_extra, char *); 1116 rules->extra = 1117 _XkbTypedReallocF(rules->extra, rules->sz_extra, 1118 XkbRF_DescribeVarsRec); 1119 } 1120 if ((!rules->extra_names) || (!rules->extra)) { 1121 PR_DEBUG("allocation error in extra parts\n"); 1122 rules->sz_extra = rules->num_extra = 0; 1123 free(rules->extra_names); 1124 rules->extra_names = NULL; 1125 free(rules->extra); 1126 rules->extra = NULL; 1127 return NULL; 1128 } 1129 rules->extra_names[rules->num_extra] = _XkbDupString(name); 1130 memset(&rules->extra[rules->num_extra], 0, sizeof(XkbRF_DescribeVarsRec)); 1131 return &rules->extra[rules->num_extra++]; 1132 } 1133 1134 Bool 1135 XkbRF_LoadDescriptions(FILE *file, XkbRF_RulesPtr rules) 1136 { 1137 InputLine line; 1138 XkbRF_VarDescRec tmp; 1139 char *tok; 1140 int len, headingtype, extra_ndx = 0; 1141 1142 memset(&tmp, 0, sizeof(XkbRF_VarDescRec)); 1143 headingtype = HEAD_NONE; 1144 InitInputLine(&line); 1145 for (; GetInputLine(file, &line, False); line.num_line = 0) { 1146 if (line.line[0] == '!') { 1147 tok = strtok(&(line.line[1]), " \t"); 1148 if (strcmp(tok, "model") == 0) 1149 headingtype = HEAD_MODEL; 1150 else if (_XkbStrCaseCmp(tok, "layout") == 0) 1151 headingtype = HEAD_LAYOUT; 1152 else if (_XkbStrCaseCmp(tok, "variant") == 0) 1153 headingtype = HEAD_VARIANT; 1154 else if (_XkbStrCaseCmp(tok, "option") == 0) 1155 headingtype = HEAD_OPTION; 1156 else { 1157 int i; 1158 1159 headingtype = HEAD_EXTRA; 1160 extra_ndx = -1; 1161 for (i = 0; (i < rules->num_extra) && (extra_ndx < 0); i++) { 1162 if (_XkbStrCaseCmp(tok, rules->extra_names[i])) 1163 extra_ndx = i; 1164 } 1165 if (extra_ndx < 0) { 1166 XkbRF_DescribeVarsPtr var; 1167 1168 PR_DEBUG1("Extra heading \"%s\" encountered\n", tok); 1169 var = XkbRF_AddVarToDescribe(rules, tok); 1170 if (var) 1171 extra_ndx = var - rules->extra; 1172 else 1173 headingtype = HEAD_NONE; 1174 } 1175 } 1176 continue; 1177 } 1178 1179 if (headingtype == HEAD_NONE) { 1180 PR_DEBUG("Must have a heading before first line of data\n"); 1181 PR_DEBUG("Illegal line of data ignored\n"); 1182 continue; 1183 } 1184 1185 len = strlen(line.line); 1186 if ((tmp.name = strtok(line.line, " \t")) == NULL) { 1187 PR_DEBUG("Huh? No token on line\n"); 1188 PR_DEBUG("Illegal line of data ignored\n"); 1189 continue; 1190 } 1191 if (strlen(tmp.name) == len) { 1192 PR_DEBUG("No description found\n"); 1193 PR_DEBUG("Illegal line of data ignored\n"); 1194 continue; 1195 } 1196 1197 tok = line.line + strlen(tmp.name) + 1; 1198 while ((*tok != '\n') && isspace(*tok)) 1199 tok++; 1200 if (*tok == '\0') { 1201 PR_DEBUG("No description found\n"); 1202 PR_DEBUG("Illegal line of data ignored\n"); 1203 continue; 1204 } 1205 tmp.desc = tok; 1206 switch (headingtype) { 1207 case HEAD_MODEL: 1208 XkbRF_AddVarDescCopy(&rules->models, &tmp); 1209 break; 1210 case HEAD_LAYOUT: 1211 XkbRF_AddVarDescCopy(&rules->layouts, &tmp); 1212 break; 1213 case HEAD_VARIANT: 1214 XkbRF_AddVarDescCopy(&rules->variants, &tmp); 1215 break; 1216 case HEAD_OPTION: 1217 XkbRF_AddVarDescCopy(&rules->options, &tmp); 1218 break; 1219 case HEAD_EXTRA: 1220 XkbRF_AddVarDescCopy(&rules->extra[extra_ndx], &tmp); 1221 break; 1222 } 1223 } 1224 FreeInputLine(&line); 1225 if ((rules->models.num_desc == 0) && (rules->layouts.num_desc == 0) && 1226 (rules->variants.num_desc == 0) && (rules->options.num_desc == 0) && 1227 (rules->num_extra == 0)) { 1228 return False; 1229 } 1230 return True; 1231 } 1232 1233 Bool 1234 XkbRF_LoadDescriptionsByName(char *base, char *locale, XkbRF_RulesPtr rules) 1235 { 1236 FILE *file; 1237 char buf[PATH_MAX]; 1238 Bool ok; 1239 1240 if ((!base) || (!rules)) 1241 return False; 1242 if (locale) { 1243 if (snprintf(buf, sizeof(buf), "%s-%s.lst", base, locale) >= (int) sizeof(buf)) 1244 return False; 1245 } 1246 else { 1247 if (snprintf(buf, sizeof(buf), "%s.lst", base) >= (int) sizeof(buf)) 1248 return False; 1249 } 1250 1251 file = fopen(buf, "r" FOPEN_CLOEXEC); 1252 if ((!file) && (locale)) { /* fallback if locale was specified */ 1253 if (snprintf(buf, sizeof(buf), "%s.lst", base) >= (int) sizeof(buf)) 1254 return False; 1255 1256 file = fopen(buf, "r" FOPEN_CLOEXEC); 1257 } 1258 if (!file) 1259 return False; 1260 ok = XkbRF_LoadDescriptions(file, rules); 1261 fclose(file); 1262 return ok; 1263 } 1264 1265 /***====================================================================***/ 1266 1267 XkbRF_RulesPtr 1268 XkbRF_Load(char *base, char *locale, Bool wantDesc, Bool wantRules) 1269 { 1270 XkbRF_RulesPtr rules; 1271 1272 if ((!base) || ((!wantDesc) && (!wantRules))) 1273 return NULL; 1274 if ((rules = _XkbTypedCalloc(1, XkbRF_RulesRec)) == NULL) 1275 return NULL; 1276 if (wantDesc && (!XkbRF_LoadDescriptionsByName(base, locale, rules))) { 1277 XkbRF_Free(rules, True); 1278 return NULL; 1279 } 1280 if (wantRules && (!XkbRF_LoadRulesByName(base, locale, rules))) { 1281 XkbRF_Free(rules, True); 1282 return NULL; 1283 } 1284 return rules; 1285 } 1286 1287 XkbRF_RulesPtr 1288 XkbRF_Create(int szRules, int szExtra) 1289 { 1290 XkbRF_RulesPtr rules; 1291 1292 if ((rules = _XkbTypedCalloc(1, XkbRF_RulesRec)) == NULL) 1293 return NULL; 1294 if (szRules > 0) { 1295 rules->sz_rules = szRules; 1296 rules->rules = _XkbTypedCalloc(rules->sz_rules, XkbRF_RuleRec); 1297 if (!rules->rules) { 1298 _XkbFree(rules); 1299 return NULL; 1300 } 1301 } 1302 if (szExtra > 0) { 1303 rules->sz_extra = szExtra; 1304 rules->extra = _XkbTypedCalloc(rules->sz_extra, XkbRF_DescribeVarsRec); 1305 if (!rules->extra) { 1306 if (rules->rules) 1307 _XkbFree(rules->rules); 1308 _XkbFree(rules); 1309 return NULL; 1310 } 1311 } 1312 return rules; 1313 } 1314 1315 /***====================================================================***/ 1316 1317 static void 1318 XkbRF_ClearVarDescriptions(XkbRF_DescribeVarsPtr var) 1319 { 1320 register int i; 1321 1322 for (i = 0; i < var->num_desc; i++) { 1323 if (var->desc[i].name) 1324 _XkbFree(var->desc[i].name); 1325 if (var->desc[i].desc) 1326 _XkbFree(var->desc[i].desc); 1327 var->desc[i].name = var->desc[i].desc = NULL; 1328 } 1329 if (var->desc) 1330 _XkbFree(var->desc); 1331 var->desc = NULL; 1332 return; 1333 } 1334 1335 void 1336 XkbRF_Free(XkbRF_RulesPtr rules, Bool freeRules) 1337 { 1338 int i; 1339 XkbRF_RulePtr rule; 1340 XkbRF_GroupPtr group; 1341 1342 if (!rules) 1343 return; 1344 XkbRF_ClearVarDescriptions(&rules->models); 1345 XkbRF_ClearVarDescriptions(&rules->layouts); 1346 XkbRF_ClearVarDescriptions(&rules->variants); 1347 XkbRF_ClearVarDescriptions(&rules->options); 1348 if (rules->extra) { 1349 for (i = 0; i < rules->num_extra; i++) { 1350 XkbRF_ClearVarDescriptions(&rules->extra[i]); 1351 } 1352 _XkbFree(rules->extra); 1353 rules->num_extra = rules->sz_extra = 0; 1354 rules->extra = NULL; 1355 } 1356 if (rules->rules) { 1357 for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) { 1358 if (rule->model) 1359 _XkbFree(rule->model); 1360 if (rule->layout) 1361 _XkbFree(rule->layout); 1362 if (rule->variant) 1363 _XkbFree(rule->variant); 1364 if (rule->option) 1365 _XkbFree(rule->option); 1366 if (rule->keycodes) 1367 _XkbFree(rule->keycodes); 1368 if (rule->symbols) 1369 _XkbFree(rule->symbols); 1370 if (rule->types) 1371 _XkbFree(rule->types); 1372 if (rule->compat) 1373 _XkbFree(rule->compat); 1374 if (rule->geometry) 1375 _XkbFree(rule->geometry); 1376 if (rule->keymap) 1377 _XkbFree(rule->keymap); 1378 memset(rule, 0, sizeof(XkbRF_RuleRec)); 1379 } 1380 _XkbFree(rules->rules); 1381 rules->num_rules = rules->sz_rules = 0; 1382 rules->rules = NULL; 1383 } 1384 1385 if (rules->groups) { 1386 for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) { 1387 if (group->name) 1388 _XkbFree(group->name); 1389 if (group->words) 1390 _XkbFree(group->words); 1391 } 1392 _XkbFree(rules->groups); 1393 rules->num_groups = 0; 1394 rules->groups = NULL; 1395 } 1396 if (freeRules) 1397 _XkbFree(rules); 1398 return; 1399 } 1400 1401 1402 Bool 1403 XkbRF_GetNamesProp(Display * dpy, char **rf_rtrn, XkbRF_VarDefsPtr vd_rtrn) 1404 { 1405 Atom rules_atom, actual_type; 1406 int fmt; 1407 unsigned long nitems, bytes_after; 1408 unsigned char *data; 1409 char *out, *end; 1410 Status rtrn; 1411 1412 rules_atom = XInternAtom(dpy, _XKB_RF_NAMES_PROP_ATOM, True); 1413 if (rules_atom == None) /* property cannot exist */ 1414 return False; 1415 rtrn = XGetWindowProperty(dpy, DefaultRootWindow(dpy), rules_atom, 1416 0L, _XKB_RF_NAMES_PROP_MAXLEN, False, 1417 XA_STRING, &actual_type, 1418 &fmt, &nitems, &bytes_after, 1419 &data); 1420 if (rtrn != Success) 1421 return False; 1422 if (rf_rtrn) 1423 *rf_rtrn = NULL; 1424 (void) memset(vd_rtrn, 0, sizeof(XkbRF_VarDefsRec)); 1425 if ((bytes_after > 0) || (actual_type != XA_STRING) || (fmt != 8)) { 1426 if (data) 1427 XFree(data); 1428 return (fmt == 0 ? True : False); 1429 } 1430 1431 out = (char *) data; 1432 end = out + nitems; 1433 if (out && (*out) && rf_rtrn) 1434 *rf_rtrn = _XkbDupString(out); 1435 out += strlen(out) + 1; 1436 1437 if (out < end) { 1438 if (*out) 1439 vd_rtrn->model = _XkbDupString(out); 1440 out += strlen(out) + 1; 1441 } 1442 1443 if (out < end) { 1444 if (*out) 1445 vd_rtrn->layout = _XkbDupString(out); 1446 out += strlen(out) + 1; 1447 } 1448 1449 if (out < end) { 1450 if (*out) 1451 vd_rtrn->variant = _XkbDupString(out); 1452 out += strlen(out) + 1; 1453 } 1454 1455 if (out < end) { 1456 if (*out) 1457 vd_rtrn->options = _XkbDupString(out); 1458 out += strlen(out) + 1; 1459 } 1460 /* 1461 * For now extra_options and extra_rules are not used 1462 * update XkbRF_FreeVarDefs if that changes 1463 */ 1464 XFree(data); 1465 return True; 1466 } 1467 1468 Bool 1469 XkbRF_SetNamesProp(Display *dpy, char *rules_file, XkbRF_VarDefsPtr var_defs) 1470 { 1471 int len, out; 1472 Atom name; 1473 char *pval; 1474 1475 len = (rules_file ? strlen(rules_file) : 0); 1476 len += (var_defs->model ? strlen(var_defs->model) : 0); 1477 len += (var_defs->layout ? strlen(var_defs->layout) : 0); 1478 len += (var_defs->variant ? strlen(var_defs->variant) : 0); 1479 len += (var_defs->options ? strlen(var_defs->options) : 0); 1480 if (len < 1) 1481 return True; 1482 1483 len += 5; /* trailing NULs */ 1484 1485 name = XInternAtom(dpy, _XKB_RF_NAMES_PROP_ATOM, False); 1486 if (name == None) { /* should never happen */ 1487 _XkbLibError(_XkbErrXReqFailure, "XkbRF_SetNamesProp", X_InternAtom); 1488 return False; 1489 } 1490 pval = (char *) _XkbAlloc(len); 1491 if (!pval) { 1492 _XkbLibError(_XkbErrBadAlloc, "XkbRF_SetNamesProp", len); 1493 return False; 1494 } 1495 out = 0; 1496 if (rules_file) { 1497 strcpy(&pval[out], rules_file); 1498 out += strlen(rules_file); 1499 } 1500 pval[out++] = '\0'; 1501 if (var_defs->model) { 1502 strcpy(&pval[out], var_defs->model); 1503 out += strlen(var_defs->model); 1504 } 1505 pval[out++] = '\0'; 1506 if (var_defs->layout) { 1507 strcpy(&pval[out], var_defs->layout); 1508 out += strlen(var_defs->layout); 1509 } 1510 pval[out++] = '\0'; 1511 if (var_defs->variant) { 1512 strcpy(&pval[out], var_defs->variant); 1513 out += strlen(var_defs->variant); 1514 } 1515 pval[out++] = '\0'; 1516 if (var_defs->options) { 1517 strcpy(&pval[out], var_defs->options); 1518 out += strlen(var_defs->options); 1519 } 1520 pval[out++] = '\0'; 1521 if (out != len) { 1522 _XkbLibError(_XkbErrBadLength, "XkbRF_SetNamesProp", out); 1523 _XkbFree(pval); 1524 return False; 1525 } 1526 1527 XChangeProperty(dpy, DefaultRootWindow(dpy), name, XA_STRING, 8, 1528 PropModeReplace, (unsigned char *) pval, len); 1529 _XkbFree(pval); 1530 return True; 1531 } 1532 1533 void 1534 XkbRF_FreeVarDefs(XkbRF_VarDefsPtr var_defs, Bool freeVarDefs) 1535 { 1536 if (!var_defs) 1537 return; 1538 1539 _XkbFree(var_defs->model); 1540 var_defs->model = NULL; 1541 _XkbFree(var_defs->layout); 1542 var_defs->layout = NULL; 1543 _XkbFree(var_defs->variant); 1544 var_defs->variant = NULL; 1545 _XkbFree(var_defs->options); 1546 var_defs->options = NULL; 1547 1548 _XkbFree(var_defs->extra_names); 1549 var_defs->extra_names = NULL; 1550 _XkbFree(var_defs->extra_values); 1551 var_defs->extra_values = NULL; 1552 1553 if(freeVarDefs) 1554 _XkbFree(var_defs); 1555 } 1556