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