105b261ecSmrg/************************************************************
205b261ecSmrg Copyright (c) 1996 by Silicon Graphics Computer Systems, Inc.
305b261ecSmrg
405b261ecSmrg Permission to use, copy, modify, and distribute this
505b261ecSmrg software and its documentation for any purpose and without
605b261ecSmrg fee is hereby granted, provided that the above copyright
705b261ecSmrg notice appear in all copies and that both that copyright
805b261ecSmrg notice and this permission notice appear in supporting
935c4bbdfSmrg documentation, and that the name of Silicon Graphics not be
1035c4bbdfSmrg used in advertising or publicity pertaining to distribution
1105b261ecSmrg of the software without specific prior written permission.
1235c4bbdfSmrg Silicon Graphics makes no representation about the suitability
1305b261ecSmrg of this software for any purpose. It is provided "as is"
1405b261ecSmrg without any express or implied warranty.
1535c4bbdfSmrg
1635c4bbdfSmrg SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1735c4bbdfSmrg SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1805b261ecSmrg AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
1935c4bbdfSmrg GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2035c4bbdfSmrg DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2135c4bbdfSmrg DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
2205b261ecSmrg OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
2305b261ecSmrg THE USE OR PERFORMANCE OF THIS SOFTWARE.
2405b261ecSmrg
2505b261ecSmrg ********************************************************/
2605b261ecSmrg
2705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2805b261ecSmrg#include <dix-config.h>
2905b261ecSmrg#endif
3005b261ecSmrg
3105b261ecSmrg#include <stdio.h>
3205b261ecSmrg#include <ctype.h>
3305b261ecSmrg#include <stdlib.h>
3405b261ecSmrg
3505b261ecSmrg#define X_INCLUDE_STRING_H
3605b261ecSmrg#define XOS_USE_NO_LOCKING
3705b261ecSmrg#include <X11/Xos_r.h>
3805b261ecSmrg
3905b261ecSmrg#include <X11/Xproto.h>
4005b261ecSmrg#include <X11/X.h>
4105b261ecSmrg#include <X11/Xos.h>
4205b261ecSmrg#include <X11/Xfuncs.h>
4305b261ecSmrg#include <X11/Xatom.h>
4405b261ecSmrg#include <X11/keysym.h>
4505b261ecSmrg#include "misc.h"
4605b261ecSmrg#include "inputstr.h"
4705b261ecSmrg#include "dix.h"
484642e01fSmrg#include "os.h"
494642e01fSmrg#include "xkbstr.h"
5005b261ecSmrg#define XKBSRV_NEED_FILE_FUNCS
5105b261ecSmrg#include <xkbsrv.h>
5205b261ecSmrg
5305b261ecSmrg/***====================================================================***/
5405b261ecSmrg
5505b261ecSmrg#define DFLT_LINE_SIZE	128
5605b261ecSmrg
5705b261ecSmrgtypedef struct {
5835c4bbdfSmrg    int line_num;
5935c4bbdfSmrg    int sz_line;
6035c4bbdfSmrg    int num_line;
6135c4bbdfSmrg    char buf[DFLT_LINE_SIZE];
6235c4bbdfSmrg    char *line;
6305b261ecSmrg} InputLine;
6405b261ecSmrg
6505b261ecSmrgstatic void
6635c4bbdfSmrgInitInputLine(InputLine * line)
6705b261ecSmrg{
6835c4bbdfSmrg    line->line_num = 1;
6935c4bbdfSmrg    line->num_line = 0;
7035c4bbdfSmrg    line->sz_line = DFLT_LINE_SIZE;
7135c4bbdfSmrg    line->line = line->buf;
7205b261ecSmrg    return;
7305b261ecSmrg}
7405b261ecSmrg
7505b261ecSmrgstatic void
7635c4bbdfSmrgFreeInputLine(InputLine * line)
7705b261ecSmrg{
7835c4bbdfSmrg    if (line->line != line->buf)
7935c4bbdfSmrg        free(line->line);
8035c4bbdfSmrg    line->line_num = 1;
8135c4bbdfSmrg    line->num_line = 0;
8235c4bbdfSmrg    line->sz_line = DFLT_LINE_SIZE;
8335c4bbdfSmrg    line->line = line->buf;
8405b261ecSmrg    return;
8505b261ecSmrg}
8605b261ecSmrg
8705b261ecSmrgstatic int
8835c4bbdfSmrgInputLineAddChar(InputLine * line, int ch)
8905b261ecSmrg{
9035c4bbdfSmrg    if (line->num_line >= line->sz_line) {
9135c4bbdfSmrg        if (line->line == line->buf) {
9235c4bbdfSmrg            line->line = xallocarray(line->sz_line, 2);
9335c4bbdfSmrg            memcpy(line->line, line->buf, line->sz_line);
9435c4bbdfSmrg        }
9535c4bbdfSmrg        else {
9635c4bbdfSmrg            line->line = reallocarray(line->line, line->sz_line, 2);
9735c4bbdfSmrg        }
9835c4bbdfSmrg        line->sz_line *= 2;
9935c4bbdfSmrg    }
10035c4bbdfSmrg    line->line[line->num_line++] = ch;
10105b261ecSmrg    return ch;
10205b261ecSmrg}
10305b261ecSmrg
10405b261ecSmrg#define	ADD_CHAR(l,c)	((l)->num_line<(l)->sz_line?\
10505b261ecSmrg				(int)((l)->line[(l)->num_line++]= (c)):\
10605b261ecSmrg				InputLineAddChar(l,c))
10705b261ecSmrg
10805b261ecSmrgstatic Bool
10935c4bbdfSmrgGetInputLine(FILE * file, InputLine * line, Bool checkbang)
11005b261ecSmrg{
11135c4bbdfSmrg    int ch;
11235c4bbdfSmrg    Bool endOfFile, spacePending, slashPending, inComment;
11335c4bbdfSmrg
11435c4bbdfSmrg    endOfFile = FALSE;
11535c4bbdfSmrg    while ((!endOfFile) && (line->num_line == 0)) {
11635c4bbdfSmrg        spacePending = slashPending = inComment = FALSE;
11735c4bbdfSmrg        while (((ch = getc(file)) != '\n') && (ch != EOF)) {
11835c4bbdfSmrg            if (ch == '\\') {
11935c4bbdfSmrg                if ((ch = getc(file)) == EOF)
12035c4bbdfSmrg                    break;
12135c4bbdfSmrg                if (ch == '\n') {
12235c4bbdfSmrg                    inComment = FALSE;
12335c4bbdfSmrg                    ch = ' ';
12435c4bbdfSmrg                    line->line_num++;
12535c4bbdfSmrg                }
12635c4bbdfSmrg            }
12735c4bbdfSmrg            if (inComment)
12835c4bbdfSmrg                continue;
12935c4bbdfSmrg            if (ch == '/') {
13035c4bbdfSmrg                if (slashPending) {
13135c4bbdfSmrg                    inComment = TRUE;
13235c4bbdfSmrg                    slashPending = FALSE;
13335c4bbdfSmrg                }
13435c4bbdfSmrg                else {
13535c4bbdfSmrg                    slashPending = TRUE;
13635c4bbdfSmrg                }
13735c4bbdfSmrg                continue;
13835c4bbdfSmrg            }
13935c4bbdfSmrg            else if (slashPending) {
14035c4bbdfSmrg                if (spacePending) {
14135c4bbdfSmrg                    ADD_CHAR(line, ' ');
14235c4bbdfSmrg                    spacePending = FALSE;
14335c4bbdfSmrg                }
14435c4bbdfSmrg                ADD_CHAR(line, '/');
14535c4bbdfSmrg                slashPending = FALSE;
14635c4bbdfSmrg            }
14735c4bbdfSmrg            if (isspace(ch)) {
14835c4bbdfSmrg                while (isspace(ch) && (ch != '\n') && (ch != EOF)) {
14935c4bbdfSmrg                    ch = getc(file);
15035c4bbdfSmrg                }
15135c4bbdfSmrg                if (ch == EOF)
15235c4bbdfSmrg                    break;
15335c4bbdfSmrg                if ((ch != '\n') && (line->num_line > 0))
15435c4bbdfSmrg                    spacePending = TRUE;
15535c4bbdfSmrg                ungetc(ch, file);
15635c4bbdfSmrg            }
15735c4bbdfSmrg            else {
15835c4bbdfSmrg                if (spacePending) {
15935c4bbdfSmrg                    ADD_CHAR(line, ' ');
16035c4bbdfSmrg                    spacePending = FALSE;
16135c4bbdfSmrg                }
16235c4bbdfSmrg                if (checkbang && ch == '!') {
16335c4bbdfSmrg                    if (line->num_line != 0) {
16435c4bbdfSmrg                        DebugF("The '!' legal only at start of line\n");
16535c4bbdfSmrg                        DebugF("Line containing '!' ignored\n");
16635c4bbdfSmrg                        line->num_line = 0;
16735c4bbdfSmrg                        inComment = 0;
16835c4bbdfSmrg                        break;
16935c4bbdfSmrg                    }
17035c4bbdfSmrg
17135c4bbdfSmrg                }
17235c4bbdfSmrg                ADD_CHAR(line, ch);
17335c4bbdfSmrg            }
17435c4bbdfSmrg        }
17535c4bbdfSmrg        if (ch == EOF)
17635c4bbdfSmrg            endOfFile = TRUE;
17705b261ecSmrg/*	else line->num_line++;*/
17835c4bbdfSmrg    }
17935c4bbdfSmrg    if ((line->num_line == 0) && (endOfFile))
18035c4bbdfSmrg        return FALSE;
18135c4bbdfSmrg    ADD_CHAR(line, '\0');
18235c4bbdfSmrg    return TRUE;
18305b261ecSmrg}
18405b261ecSmrg
18505b261ecSmrg/***====================================================================***/
18605b261ecSmrg
18705b261ecSmrg#define	MODEL		0
18805b261ecSmrg#define	LAYOUT		1
18905b261ecSmrg#define	VARIANT		2
19005b261ecSmrg#define	OPTION		3
19105b261ecSmrg#define	KEYCODES	4
19205b261ecSmrg#define SYMBOLS		5
19305b261ecSmrg#define	TYPES		6
19405b261ecSmrg#define	COMPAT		7
19505b261ecSmrg#define	GEOMETRY	8
1966747b715Smrg#define	MAX_WORDS	9
19705b261ecSmrg
19805b261ecSmrg#define	PART_MASK	0x000F
19905b261ecSmrg#define	COMPONENT_MASK	0x03F0
20005b261ecSmrg
20135c4bbdfSmrgstatic const char *cname[MAX_WORDS] = {
20235c4bbdfSmrg    "model", "layout", "variant", "option",
20335c4bbdfSmrg    "keycodes", "symbols", "types", "compat", "geometry"
20405b261ecSmrg};
20505b261ecSmrg
20635c4bbdfSmrgtypedef struct _RemapSpec {
20735c4bbdfSmrg    int number;
20835c4bbdfSmrg    int num_remap;
20935c4bbdfSmrg    struct {
21035c4bbdfSmrg        int word;
21135c4bbdfSmrg        int index;
21235c4bbdfSmrg    } remap[MAX_WORDS];
21305b261ecSmrg} RemapSpec;
21405b261ecSmrg
21505b261ecSmrgtypedef struct _FileSpec {
21635c4bbdfSmrg    char *name[MAX_WORDS];
21735c4bbdfSmrg    struct _FileSpec *pending;
21805b261ecSmrg} FileSpec;
21905b261ecSmrg
22005b261ecSmrgtypedef struct {
22135c4bbdfSmrg    const char *model;
22235c4bbdfSmrg    const char *layout[XkbNumKbdGroups + 1];
22335c4bbdfSmrg    const char *variant[XkbNumKbdGroups + 1];
22435c4bbdfSmrg    const char *options;
22505b261ecSmrg} XkbRF_MultiDefsRec, *XkbRF_MultiDefsPtr;
22605b261ecSmrg
22705b261ecSmrg#define NDX_BUFF_SIZE	4
22805b261ecSmrg
22905b261ecSmrg/***====================================================================***/
23005b261ecSmrg
23135c4bbdfSmrgstatic char *
23205b261ecSmrgget_index(char *str, int *ndx)
23305b261ecSmrg{
23435c4bbdfSmrg    char ndx_buf[NDX_BUFF_SIZE];
23535c4bbdfSmrg    char *end;
23635c4bbdfSmrg
23735c4bbdfSmrg    if (*str != '[') {
23835c4bbdfSmrg        *ndx = 0;
23935c4bbdfSmrg        return str;
24035c4bbdfSmrg    }
24135c4bbdfSmrg    str++;
24235c4bbdfSmrg    end = strchr(str, ']');
24335c4bbdfSmrg    if (end == NULL) {
24435c4bbdfSmrg        *ndx = -1;
24535c4bbdfSmrg        return str - 1;
24635c4bbdfSmrg    }
24735c4bbdfSmrg    if ((end - str) >= NDX_BUFF_SIZE) {
24835c4bbdfSmrg        *ndx = -1;
24935c4bbdfSmrg        return end + 1;
25035c4bbdfSmrg    }
25135c4bbdfSmrg    strlcpy(ndx_buf, str, 1 + end - str);
25235c4bbdfSmrg    *ndx = atoi(ndx_buf);
25335c4bbdfSmrg    return end + 1;
25405b261ecSmrg}
25505b261ecSmrg
25605b261ecSmrgstatic void
25735c4bbdfSmrgSetUpRemap(InputLine * line, RemapSpec * remap)
25805b261ecSmrg{
25935c4bbdfSmrg    char *tok, *str;
26035c4bbdfSmrg    unsigned present, l_ndx_present, v_ndx_present;
26135c4bbdfSmrg    register int i;
26235c4bbdfSmrg    int len, ndx;
26335c4bbdfSmrg    _Xstrtokparams strtok_buf;
26435c4bbdfSmrg    Bool found;
26535c4bbdfSmrg
26635c4bbdfSmrg    l_ndx_present = v_ndx_present = present = 0;
26735c4bbdfSmrg    str = &line->line[1];
26835c4bbdfSmrg    len = remap->number;
26935c4bbdfSmrg    memset((char *) remap, 0, sizeof(RemapSpec));
27035c4bbdfSmrg    remap->number = len;
27135c4bbdfSmrg    while ((tok = _XStrtok(str, " ", strtok_buf)) != NULL) {
27235c4bbdfSmrg        found = FALSE;
27335c4bbdfSmrg        str = NULL;
27435c4bbdfSmrg        if (strcmp(tok, "=") == 0)
27535c4bbdfSmrg            continue;
27635c4bbdfSmrg        for (i = 0; i < MAX_WORDS; i++) {
27705b261ecSmrg            len = strlen(cname[i]);
27835c4bbdfSmrg            if (strncmp(cname[i], tok, len) == 0) {
27935c4bbdfSmrg                if (strlen(tok) > len) {
28035c4bbdfSmrg                    char *end = get_index(tok + len, &ndx);
28135c4bbdfSmrg
28235c4bbdfSmrg                    if ((i != LAYOUT && i != VARIANT) ||
28335c4bbdfSmrg                        *end != '\0' || ndx == -1)
28435c4bbdfSmrg                        break;
28535c4bbdfSmrg                    if (ndx < 1 || ndx > XkbNumKbdGroups) {
28635c4bbdfSmrg                        DebugF("Illegal %s index: %d\n", cname[i], ndx);
28735c4bbdfSmrg                        DebugF("Index must be in range 1..%d\n",
28835c4bbdfSmrg                               XkbNumKbdGroups);
28935c4bbdfSmrg                        break;
29035c4bbdfSmrg                    }
29135c4bbdfSmrg                }
29235c4bbdfSmrg                else {
29335c4bbdfSmrg                    ndx = 0;
29405b261ecSmrg                }
29535c4bbdfSmrg                found = TRUE;
29635c4bbdfSmrg                if (present & (1 << i)) {
29735c4bbdfSmrg                    if ((i == LAYOUT && l_ndx_present & (1 << ndx)) ||
29835c4bbdfSmrg                        (i == VARIANT && v_ndx_present & (1 << ndx))) {
29935c4bbdfSmrg                        DebugF("Component \"%s\" listed twice\n", tok);
30035c4bbdfSmrg                        DebugF("Second definition ignored\n");
30135c4bbdfSmrg                        break;
30235c4bbdfSmrg                    }
30335c4bbdfSmrg                }
30435c4bbdfSmrg                present |= (1 << i);
30505b261ecSmrg                if (i == LAYOUT)
30605b261ecSmrg                    l_ndx_present |= 1 << ndx;
30705b261ecSmrg                if (i == VARIANT)
30805b261ecSmrg                    v_ndx_present |= 1 << ndx;
30935c4bbdfSmrg                remap->remap[remap->num_remap].word = i;
31035c4bbdfSmrg                remap->remap[remap->num_remap++].index = ndx;
31135c4bbdfSmrg                break;
31235c4bbdfSmrg            }
31335c4bbdfSmrg        }
31435c4bbdfSmrg        if (!found) {
31535c4bbdfSmrg            fprintf(stderr, "Unknown component \"%s\" ignored\n", tok);
31635c4bbdfSmrg        }
31735c4bbdfSmrg    }
31835c4bbdfSmrg    if ((present & PART_MASK) == 0) {
31935c4bbdfSmrg        unsigned mask = PART_MASK;
32035c4bbdfSmrg
32135c4bbdfSmrg        ErrorF("Mapping needs at least one of ");
32235c4bbdfSmrg        for (i = 0; (i < MAX_WORDS); i++) {
32335c4bbdfSmrg            if ((1L << i) & mask) {
32435c4bbdfSmrg                mask &= ~(1L << i);
32535c4bbdfSmrg                if (mask)
32635c4bbdfSmrg                    DebugF("\"%s,\" ", cname[i]);
32735c4bbdfSmrg                else
32835c4bbdfSmrg                    DebugF("or \"%s\"\n", cname[i]);
32935c4bbdfSmrg            }
33035c4bbdfSmrg        }
33135c4bbdfSmrg        DebugF("Illegal mapping ignored\n");
33235c4bbdfSmrg        remap->num_remap = 0;
33335c4bbdfSmrg        return;
33435c4bbdfSmrg    }
33535c4bbdfSmrg    if ((present & COMPONENT_MASK) == 0) {
33635c4bbdfSmrg        DebugF("Mapping needs at least one component\n");
33735c4bbdfSmrg        DebugF("Illegal mapping ignored\n");
33835c4bbdfSmrg        remap->num_remap = 0;
33935c4bbdfSmrg        return;
34035c4bbdfSmrg    }
34135c4bbdfSmrg    remap->number++;
34235c4bbdfSmrg    return;
34305b261ecSmrg}
34405b261ecSmrg
34505b261ecSmrgstatic Bool
34635c4bbdfSmrgMatchOneOf(const char *wanted, const char *vals_defined)
34705b261ecSmrg{
34835c4bbdfSmrg    const char *str, *next;
34935c4bbdfSmrg    int want_len = strlen(wanted);
35035c4bbdfSmrg
35135c4bbdfSmrg    for (str = vals_defined, next = NULL; str != NULL; str = next) {
35235c4bbdfSmrg        int len;
35335c4bbdfSmrg
35435c4bbdfSmrg        next = strchr(str, ',');
35535c4bbdfSmrg        if (next) {
35635c4bbdfSmrg            len = next - str;
35735c4bbdfSmrg            next++;
35835c4bbdfSmrg        }
35935c4bbdfSmrg        else {
36035c4bbdfSmrg            len = strlen(str);
36135c4bbdfSmrg        }
36235c4bbdfSmrg        if ((len == want_len) && (strncmp(wanted, str, len) == 0))
36335c4bbdfSmrg            return TRUE;
36405b261ecSmrg    }
3656747b715Smrg    return FALSE;
36605b261ecSmrg}
36705b261ecSmrg
36805b261ecSmrg/***====================================================================***/
36905b261ecSmrg
37005b261ecSmrgstatic Bool
37135c4bbdfSmrgCheckLine(InputLine * line,
37235c4bbdfSmrg          RemapSpec * remap, XkbRF_RulePtr rule, XkbRF_GroupPtr group)
37305b261ecSmrg{
37435c4bbdfSmrg    char *str, *tok;
37535c4bbdfSmrg    register int nread, i;
37635c4bbdfSmrg    FileSpec tmp;
37735c4bbdfSmrg    _Xstrtokparams strtok_buf;
37835c4bbdfSmrg    Bool append = FALSE;
37905b261ecSmrg
38035c4bbdfSmrg    if (line->line[0] == '!') {
38105b261ecSmrg        if (line->line[1] == '$' ||
38205b261ecSmrg            (line->line[1] == ' ' && line->line[2] == '$')) {
38305b261ecSmrg            char *gname = strchr(line->line, '$');
38405b261ecSmrg            char *words = strchr(gname, ' ');
38535c4bbdfSmrg
38635c4bbdfSmrg            if (!words)
3876747b715Smrg                return FALSE;
38805b261ecSmrg            *words++ = '\0';
38905b261ecSmrg            for (; *words; words++) {
39005b261ecSmrg                if (*words != '=' && *words != ' ')
39105b261ecSmrg                    break;
39205b261ecSmrg            }
39305b261ecSmrg            if (*words == '\0')
3946747b715Smrg                return FALSE;
39535c4bbdfSmrg            group->name = Xstrdup(gname);
39635c4bbdfSmrg            group->words = Xstrdup(words);
39705b261ecSmrg            for (i = 1, words = group->words; *words; words++) {
39835c4bbdfSmrg                if (*words == ' ') {
39935c4bbdfSmrg                    *words++ = '\0';
40035c4bbdfSmrg                    i++;
40135c4bbdfSmrg                }
40205b261ecSmrg            }
40305b261ecSmrg            group->number = i;
4046747b715Smrg            return TRUE;
40535c4bbdfSmrg        }
40635c4bbdfSmrg        else {
40735c4bbdfSmrg            SetUpRemap(line, remap);
40835c4bbdfSmrg            return FALSE;
40935c4bbdfSmrg        }
41035c4bbdfSmrg    }
41135c4bbdfSmrg
41235c4bbdfSmrg    if (remap->num_remap == 0) {
41335c4bbdfSmrg        DebugF("Must have a mapping before first line of data\n");
41435c4bbdfSmrg        DebugF("Illegal line of data ignored\n");
41535c4bbdfSmrg        return FALSE;
41635c4bbdfSmrg    }
41735c4bbdfSmrg    memset((char *) &tmp, 0, sizeof(FileSpec));
41835c4bbdfSmrg    str = line->line;
41935c4bbdfSmrg    for (nread = 0; (tok = _XStrtok(str, " ", strtok_buf)) != NULL; nread++) {
42035c4bbdfSmrg        str = NULL;
42135c4bbdfSmrg        if (strcmp(tok, "=") == 0) {
42235c4bbdfSmrg            nread--;
42335c4bbdfSmrg            continue;
42435c4bbdfSmrg        }
42535c4bbdfSmrg        if (nread > remap->num_remap) {
42635c4bbdfSmrg            DebugF("Too many words on a line\n");
42735c4bbdfSmrg            DebugF("Extra word \"%s\" ignored\n", tok);
42835c4bbdfSmrg            continue;
42935c4bbdfSmrg        }
43035c4bbdfSmrg        tmp.name[remap->remap[nread].word] = tok;
43135c4bbdfSmrg        if (*tok == '+' || *tok == '|')
43235c4bbdfSmrg            append = TRUE;
43335c4bbdfSmrg    }
43435c4bbdfSmrg    if (nread < remap->num_remap) {
43535c4bbdfSmrg        DebugF("Too few words on a line: %s\n", line->line);
43635c4bbdfSmrg        DebugF("line ignored\n");
43735c4bbdfSmrg        return FALSE;
43835c4bbdfSmrg    }
43935c4bbdfSmrg
44035c4bbdfSmrg    rule->flags = 0;
44105b261ecSmrg    rule->number = remap->number;
44205b261ecSmrg    if (tmp.name[OPTION])
44335c4bbdfSmrg        rule->flags |= XkbRF_Option;
44405b261ecSmrg    else if (append)
44535c4bbdfSmrg        rule->flags |= XkbRF_Append;
44605b261ecSmrg    else
44735c4bbdfSmrg        rule->flags |= XkbRF_Normal;
44835c4bbdfSmrg    rule->model = Xstrdup(tmp.name[MODEL]);
44935c4bbdfSmrg    rule->layout = Xstrdup(tmp.name[LAYOUT]);
45035c4bbdfSmrg    rule->variant = Xstrdup(tmp.name[VARIANT]);
45135c4bbdfSmrg    rule->option = Xstrdup(tmp.name[OPTION]);
45235c4bbdfSmrg
45335c4bbdfSmrg    rule->keycodes = Xstrdup(tmp.name[KEYCODES]);
45435c4bbdfSmrg    rule->symbols = Xstrdup(tmp.name[SYMBOLS]);
45535c4bbdfSmrg    rule->types = Xstrdup(tmp.name[TYPES]);
45635c4bbdfSmrg    rule->compat = Xstrdup(tmp.name[COMPAT]);
45735c4bbdfSmrg    rule->geometry = Xstrdup(tmp.name[GEOMETRY]);
45805b261ecSmrg
45905b261ecSmrg    rule->layout_num = rule->variant_num = 0;
46005b261ecSmrg    for (i = 0; i < nread; i++) {
46105b261ecSmrg        if (remap->remap[i].index) {
46235c4bbdfSmrg            if (remap->remap[i].word == LAYOUT)
46335c4bbdfSmrg                rule->layout_num = remap->remap[i].index;
46435c4bbdfSmrg            if (remap->remap[i].word == VARIANT)
46535c4bbdfSmrg                rule->variant_num = remap->remap[i].index;
46605b261ecSmrg        }
46705b261ecSmrg    }
4686747b715Smrg    return TRUE;
46905b261ecSmrg}
47005b261ecSmrg
47105b261ecSmrgstatic char *
47235c4bbdfSmrg_Concat(char *str1, const char *str2)
47305b261ecSmrg{
47435c4bbdfSmrg    int len;
47505b261ecSmrg
47635c4bbdfSmrg    if ((!str1) || (!str2))
47735c4bbdfSmrg        return str1;
47835c4bbdfSmrg    len = strlen(str1) + strlen(str2) + 1;
47935c4bbdfSmrg    str1 = realloc(str1, len * sizeof(char));
48005b261ecSmrg    if (str1)
48135c4bbdfSmrg        strcat(str1, str2);
48205b261ecSmrg    return str1;
48305b261ecSmrg}
48405b261ecSmrg
48505b261ecSmrgstatic void
48605b261ecSmrgsqueeze_spaces(char *p1)
48705b261ecSmrg{
48835c4bbdfSmrg    char *p2;
48935c4bbdfSmrg
49035c4bbdfSmrg    for (p2 = p1; *p2; p2++) {
49135c4bbdfSmrg        *p1 = *p2;
49235c4bbdfSmrg        if (*p1 != ' ')
49335c4bbdfSmrg            p1++;
49435c4bbdfSmrg    }
49535c4bbdfSmrg    *p1 = '\0';
49605b261ecSmrg}
49705b261ecSmrg
49805b261ecSmrgstatic Bool
49905b261ecSmrgMakeMultiDefs(XkbRF_MultiDefsPtr mdefs, XkbRF_VarDefsPtr defs)
50005b261ecSmrg{
50135c4bbdfSmrg    char *options;
50235c4bbdfSmrg    memset((char *) mdefs, 0, sizeof(XkbRF_MultiDefsRec));
50335c4bbdfSmrg    mdefs->model = defs->model;
50435c4bbdfSmrg    options = Xstrdup(defs->options);
50535c4bbdfSmrg    if (options)
50635c4bbdfSmrg        squeeze_spaces(options);
50735c4bbdfSmrg    mdefs->options = options;
50835c4bbdfSmrg
50935c4bbdfSmrg    if (defs->layout) {
51035c4bbdfSmrg        if (!strchr(defs->layout, ',')) {
51135c4bbdfSmrg            mdefs->layout[0] = defs->layout;
51235c4bbdfSmrg        }
51335c4bbdfSmrg        else {
51435c4bbdfSmrg            char *p;
51535c4bbdfSmrg            char *layout;
51635c4bbdfSmrg            int i;
51705b261ecSmrg
51835c4bbdfSmrg            layout = Xstrdup(defs->layout);
51935c4bbdfSmrg            if (layout == NULL)
52035c4bbdfSmrg                return FALSE;
52135c4bbdfSmrg            squeeze_spaces(layout);
52235c4bbdfSmrg            mdefs->layout[1] = layout;
52335c4bbdfSmrg            p = layout;
52435c4bbdfSmrg            for (i = 2; i <= XkbNumKbdGroups; i++) {
52535c4bbdfSmrg                if ((p = strchr(p, ','))) {
52635c4bbdfSmrg                    *p++ = '\0';
52735c4bbdfSmrg                    mdefs->layout[i] = p;
52835c4bbdfSmrg                }
52935c4bbdfSmrg                else {
53035c4bbdfSmrg                    break;
53135c4bbdfSmrg                }
53235c4bbdfSmrg            }
53335c4bbdfSmrg            if (p && (p = strchr(p, ',')))
53435c4bbdfSmrg                *p = '\0';
53535c4bbdfSmrg        }
53635c4bbdfSmrg    }
53735c4bbdfSmrg
53835c4bbdfSmrg    if (defs->variant) {
53935c4bbdfSmrg        if (!strchr(defs->variant, ',')) {
54035c4bbdfSmrg            mdefs->variant[0] = defs->variant;
54135c4bbdfSmrg        }
54235c4bbdfSmrg        else {
54335c4bbdfSmrg            char *p;
54435c4bbdfSmrg            char *variant;
54535c4bbdfSmrg            int i;
54635c4bbdfSmrg
54735c4bbdfSmrg            variant = Xstrdup(defs->variant);
54835c4bbdfSmrg            if (variant == NULL)
54935c4bbdfSmrg                return FALSE;
55035c4bbdfSmrg            squeeze_spaces(variant);
55135c4bbdfSmrg            mdefs->variant[1] = variant;
55235c4bbdfSmrg            p = variant;
55335c4bbdfSmrg            for (i = 2; i <= XkbNumKbdGroups; i++) {
55435c4bbdfSmrg                if ((p = strchr(p, ','))) {
55535c4bbdfSmrg                    *p++ = '\0';
55635c4bbdfSmrg                    mdefs->variant[i] = p;
55735c4bbdfSmrg                }
55835c4bbdfSmrg                else {
55935c4bbdfSmrg                    break;
56035c4bbdfSmrg                }
56135c4bbdfSmrg            }
56235c4bbdfSmrg            if (p && (p = strchr(p, ',')))
56335c4bbdfSmrg                *p = '\0';
56435c4bbdfSmrg        }
56535c4bbdfSmrg    }
56635c4bbdfSmrg    return TRUE;
56705b261ecSmrg}
56805b261ecSmrg
56905b261ecSmrgstatic void
57005b261ecSmrgFreeMultiDefs(XkbRF_MultiDefsPtr defs)
57105b261ecSmrg{
57235c4bbdfSmrg    free((void *) defs->options);
57335c4bbdfSmrg    free((void *) defs->layout[1]);
57435c4bbdfSmrg    free((void *) defs->variant[1]);
57505b261ecSmrg}
57605b261ecSmrg
57705b261ecSmrgstatic void
57835c4bbdfSmrgApply(const char *src, char **dst)
57905b261ecSmrg{
58005b261ecSmrg    if (src) {
5811b5d61b8Smrg        if (*src == '+' || *src == '|') {
58235c4bbdfSmrg            *dst = _Concat(*dst, src);
58335c4bbdfSmrg        }
58435c4bbdfSmrg        else {
58505b261ecSmrg            if (*dst == NULL)
58635c4bbdfSmrg                *dst = Xstrdup(src);
58705b261ecSmrg        }
58805b261ecSmrg    }
58905b261ecSmrg}
59005b261ecSmrg
59105b261ecSmrgstatic void
59235c4bbdfSmrgXkbRF_ApplyRule(XkbRF_RulePtr rule, XkbComponentNamesPtr names)
59305b261ecSmrg{
59435c4bbdfSmrg    rule->flags &= ~XkbRF_PendingMatch; /* clear the flag because it's applied */
59505b261ecSmrg
59605b261ecSmrg    Apply(rule->keycodes, &names->keycodes);
59735c4bbdfSmrg    Apply(rule->symbols, &names->symbols);
59835c4bbdfSmrg    Apply(rule->types, &names->types);
59935c4bbdfSmrg    Apply(rule->compat, &names->compat);
60005b261ecSmrg    Apply(rule->geometry, &names->geometry);
60105b261ecSmrg}
60205b261ecSmrg
60305b261ecSmrgstatic Bool
60435c4bbdfSmrgCheckGroup(XkbRF_RulesPtr rules, const char *group_name, const char *name)
60505b261ecSmrg{
60635c4bbdfSmrg    int i;
60735c4bbdfSmrg    char *p;
60835c4bbdfSmrg    XkbRF_GroupPtr group;
60935c4bbdfSmrg
61035c4bbdfSmrg    for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
61135c4bbdfSmrg        if (!strcmp(group->name, group_name)) {
61235c4bbdfSmrg            break;
61335c4bbdfSmrg        }
61435c4bbdfSmrg    }
61535c4bbdfSmrg    if (i == rules->num_groups)
61635c4bbdfSmrg        return FALSE;
61735c4bbdfSmrg    for (i = 0, p = group->words; i < group->number; i++, p += strlen(p) + 1) {
61835c4bbdfSmrg        if (!strcmp(p, name)) {
61935c4bbdfSmrg            return TRUE;
62035c4bbdfSmrg        }
62135c4bbdfSmrg    }
62235c4bbdfSmrg    return FALSE;
62305b261ecSmrg}
62405b261ecSmrg
62505b261ecSmrgstatic int
62635c4bbdfSmrgXkbRF_CheckApplyRule(XkbRF_RulePtr rule,
62735c4bbdfSmrg                     XkbRF_MultiDefsPtr mdefs,
62835c4bbdfSmrg                     XkbComponentNamesPtr names, XkbRF_RulesPtr rules)
62905b261ecSmrg{
6306747b715Smrg    Bool pending = FALSE;
63105b261ecSmrg
63205b261ecSmrg    if (rule->model != NULL) {
63335c4bbdfSmrg        if (mdefs->model == NULL)
63405b261ecSmrg            return 0;
63505b261ecSmrg        if (strcmp(rule->model, "*") == 0) {
6366747b715Smrg            pending = TRUE;
63735c4bbdfSmrg        }
63835c4bbdfSmrg        else {
63905b261ecSmrg            if (rule->model[0] == '$') {
64035c4bbdfSmrg                if (!CheckGroup(rules, rule->model, mdefs->model))
64135c4bbdfSmrg                    return 0;
64235c4bbdfSmrg            }
64335c4bbdfSmrg            else {
64435c4bbdfSmrg                if (strcmp(rule->model, mdefs->model) != 0)
64535c4bbdfSmrg                    return 0;
64635c4bbdfSmrg            }
64735c4bbdfSmrg        }
64805b261ecSmrg    }
64905b261ecSmrg    if (rule->option != NULL) {
65035c4bbdfSmrg        if (mdefs->options == NULL)
65135c4bbdfSmrg            return 0;
65235c4bbdfSmrg        if ((!MatchOneOf(rule->option, mdefs->options)))
65335c4bbdfSmrg            return 0;
65405b261ecSmrg    }
65505b261ecSmrg
65605b261ecSmrg    if (rule->layout != NULL) {
65735c4bbdfSmrg        if (mdefs->layout[rule->layout_num] == NULL ||
65835c4bbdfSmrg            *mdefs->layout[rule->layout_num] == '\0')
65935c4bbdfSmrg            return 0;
66005b261ecSmrg        if (strcmp(rule->layout, "*") == 0) {
6616747b715Smrg            pending = TRUE;
66235c4bbdfSmrg        }
66335c4bbdfSmrg        else {
66405b261ecSmrg            if (rule->layout[0] == '$') {
66535c4bbdfSmrg                if (!CheckGroup(rules, rule->layout,
66635c4bbdfSmrg                                mdefs->layout[rule->layout_num]))
66735c4bbdfSmrg                    return 0;
66835c4bbdfSmrg            }
66935c4bbdfSmrg            else {
67035c4bbdfSmrg                if (strcmp(rule->layout, mdefs->layout[rule->layout_num]) != 0)
67135c4bbdfSmrg                    return 0;
67235c4bbdfSmrg            }
67335c4bbdfSmrg        }
67405b261ecSmrg    }
67505b261ecSmrg    if (rule->variant != NULL) {
67635c4bbdfSmrg        if (mdefs->variant[rule->variant_num] == NULL ||
67735c4bbdfSmrg            *mdefs->variant[rule->variant_num] == '\0')
67835c4bbdfSmrg            return 0;
67905b261ecSmrg        if (strcmp(rule->variant, "*") == 0) {
6806747b715Smrg            pending = TRUE;
68135c4bbdfSmrg        }
68235c4bbdfSmrg        else {
68305b261ecSmrg            if (rule->variant[0] == '$') {
68435c4bbdfSmrg                if (!CheckGroup(rules, rule->variant,
68535c4bbdfSmrg                                mdefs->variant[rule->variant_num]))
68635c4bbdfSmrg                    return 0;
68735c4bbdfSmrg            }
68835c4bbdfSmrg            else {
68935c4bbdfSmrg                if (strcmp(rule->variant,
69035c4bbdfSmrg                           mdefs->variant[rule->variant_num]) != 0)
69135c4bbdfSmrg                    return 0;
69235c4bbdfSmrg            }
69335c4bbdfSmrg        }
69405b261ecSmrg    }
69505b261ecSmrg    if (pending) {
69635c4bbdfSmrg        rule->flags |= XkbRF_PendingMatch;
69735c4bbdfSmrg        return rule->number;
69805b261ecSmrg    }
69905b261ecSmrg    /* exact match, apply it now */
70035c4bbdfSmrg    XkbRF_ApplyRule(rule, names);
70105b261ecSmrg    return rule->number;
70205b261ecSmrg}
70305b261ecSmrg
70405b261ecSmrgstatic void
70505b261ecSmrgXkbRF_ClearPartialMatches(XkbRF_RulesPtr rules)
70605b261ecSmrg{
70735c4bbdfSmrg    register int i;
70835c4bbdfSmrg    XkbRF_RulePtr rule;
70905b261ecSmrg
71035c4bbdfSmrg    for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) {
71135c4bbdfSmrg        rule->flags &= ~XkbRF_PendingMatch;
71205b261ecSmrg    }
71305b261ecSmrg}
71405b261ecSmrg
71505b261ecSmrgstatic void
71635c4bbdfSmrgXkbRF_ApplyPartialMatches(XkbRF_RulesPtr rules, XkbComponentNamesPtr names)
71705b261ecSmrg{
71835c4bbdfSmrg    int i;
71935c4bbdfSmrg    XkbRF_RulePtr rule;
72005b261ecSmrg
72105b261ecSmrg    for (rule = rules->rules, i = 0; i < rules->num_rules; i++, rule++) {
72235c4bbdfSmrg        if ((rule->flags & XkbRF_PendingMatch) == 0)
72335c4bbdfSmrg            continue;
72435c4bbdfSmrg        XkbRF_ApplyRule(rule, names);
72505b261ecSmrg    }
72605b261ecSmrg}
72705b261ecSmrg
72805b261ecSmrgstatic void
72935c4bbdfSmrgXkbRF_CheckApplyRules(XkbRF_RulesPtr rules,
73035c4bbdfSmrg                      XkbRF_MultiDefsPtr mdefs,
73135c4bbdfSmrg                      XkbComponentNamesPtr names, int flags)
73205b261ecSmrg{
73335c4bbdfSmrg    int i;
73435c4bbdfSmrg    XkbRF_RulePtr rule;
73535c4bbdfSmrg    int skip;
73635c4bbdfSmrg
73735c4bbdfSmrg    for (rule = rules->rules, i = 0; i < rules->num_rules; rule++, i++) {
73835c4bbdfSmrg        if ((rule->flags & flags) != flags)
73935c4bbdfSmrg            continue;
74035c4bbdfSmrg        skip = XkbRF_CheckApplyRule(rule, mdefs, names, rules);
74135c4bbdfSmrg        if (skip && !(flags & XkbRF_Option)) {
74235c4bbdfSmrg            for (; (i < rules->num_rules) && (rule->number == skip);
74335c4bbdfSmrg                 rule++, i++);
74435c4bbdfSmrg            rule--;
74535c4bbdfSmrg            i--;
74635c4bbdfSmrg        }
74705b261ecSmrg    }
74805b261ecSmrg}
74905b261ecSmrg
75005b261ecSmrg/***====================================================================***/
75105b261ecSmrg
75205b261ecSmrgstatic char *
75305b261ecSmrgXkbRF_SubstituteVars(char *name, XkbRF_MultiDefsPtr mdefs)
75405b261ecSmrg{
75535c4bbdfSmrg    char *str, *outstr, *orig, *var;
75635c4bbdfSmrg    int len, ndx;
75735c4bbdfSmrg
75835c4bbdfSmrg    orig = name;
75935c4bbdfSmrg    str = index(name, '%');
76035c4bbdfSmrg    if (str == NULL)
76135c4bbdfSmrg        return name;
76235c4bbdfSmrg    len = strlen(name);
76335c4bbdfSmrg    while (str != NULL) {
76435c4bbdfSmrg        char pfx = str[1];
76535c4bbdfSmrg        int extra_len = 0;
76635c4bbdfSmrg
76735c4bbdfSmrg        if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) {
76835c4bbdfSmrg            extra_len = 1;
76935c4bbdfSmrg            str++;
77035c4bbdfSmrg        }
77135c4bbdfSmrg        else if (pfx == '(') {
77235c4bbdfSmrg            extra_len = 2;
77335c4bbdfSmrg            str++;
77435c4bbdfSmrg        }
77535c4bbdfSmrg        var = str + 1;
77635c4bbdfSmrg        str = get_index(var + 1, &ndx);
77735c4bbdfSmrg        if (ndx == -1) {
77835c4bbdfSmrg            str = index(str, '%');
77935c4bbdfSmrg            continue;
78035c4bbdfSmrg        }
78135c4bbdfSmrg        if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx])
78235c4bbdfSmrg            len += strlen(mdefs->layout[ndx]) + extra_len;
78335c4bbdfSmrg        else if ((*var == 'm') && mdefs->model)
78435c4bbdfSmrg            len += strlen(mdefs->model) + extra_len;
78535c4bbdfSmrg        else if ((*var == 'v') && mdefs->variant[ndx] && *mdefs->variant[ndx])
78635c4bbdfSmrg            len += strlen(mdefs->variant[ndx]) + extra_len;
78735c4bbdfSmrg        if ((pfx == '(') && (*str == ')')) {
78835c4bbdfSmrg            str++;
78935c4bbdfSmrg        }
79035c4bbdfSmrg        str = index(&str[0], '%');
79135c4bbdfSmrg    }
79235c4bbdfSmrg    name = malloc(len + 1);
79335c4bbdfSmrg    str = orig;
79435c4bbdfSmrg    outstr = name;
79535c4bbdfSmrg    while (*str != '\0') {
79635c4bbdfSmrg        if (str[0] == '%') {
79735c4bbdfSmrg            char pfx, sfx;
79835c4bbdfSmrg
79935c4bbdfSmrg            str++;
80035c4bbdfSmrg            pfx = str[0];
80135c4bbdfSmrg            sfx = '\0';
80235c4bbdfSmrg            if ((pfx == '+') || (pfx == '|') || (pfx == '_') || (pfx == '-')) {
80335c4bbdfSmrg                str++;
80405b261ecSmrg            }
80535c4bbdfSmrg            else if (pfx == '(') {
80635c4bbdfSmrg                sfx = ')';
80735c4bbdfSmrg                str++;
80835c4bbdfSmrg            }
80935c4bbdfSmrg            else
81035c4bbdfSmrg                pfx = '\0';
81135c4bbdfSmrg
81235c4bbdfSmrg            var = str;
81335c4bbdfSmrg            str = get_index(var + 1, &ndx);
81435c4bbdfSmrg            if (ndx == -1) {
81535c4bbdfSmrg                continue;
81635c4bbdfSmrg            }
81735c4bbdfSmrg            if ((*var == 'l') && mdefs->layout[ndx] && *mdefs->layout[ndx]) {
81835c4bbdfSmrg                if (pfx)
81935c4bbdfSmrg                    *outstr++ = pfx;
82035c4bbdfSmrg                strcpy(outstr, mdefs->layout[ndx]);
82135c4bbdfSmrg                outstr += strlen(mdefs->layout[ndx]);
82235c4bbdfSmrg                if (sfx)
82335c4bbdfSmrg                    *outstr++ = sfx;
82435c4bbdfSmrg            }
82535c4bbdfSmrg            else if ((*var == 'm') && (mdefs->model)) {
82635c4bbdfSmrg                if (pfx)
82735c4bbdfSmrg                    *outstr++ = pfx;
82835c4bbdfSmrg                strcpy(outstr, mdefs->model);
82935c4bbdfSmrg                outstr += strlen(mdefs->model);
83035c4bbdfSmrg                if (sfx)
83135c4bbdfSmrg                    *outstr++ = sfx;
83235c4bbdfSmrg            }
83335c4bbdfSmrg            else if ((*var == 'v') && mdefs->variant[ndx] &&
83435c4bbdfSmrg                     *mdefs->variant[ndx]) {
83535c4bbdfSmrg                if (pfx)
83635c4bbdfSmrg                    *outstr++ = pfx;
83735c4bbdfSmrg                strcpy(outstr, mdefs->variant[ndx]);
83835c4bbdfSmrg                outstr += strlen(mdefs->variant[ndx]);
83935c4bbdfSmrg                if (sfx)
84035c4bbdfSmrg                    *outstr++ = sfx;
84135c4bbdfSmrg            }
84235c4bbdfSmrg            if ((pfx == '(') && (*str == ')'))
84335c4bbdfSmrg                str++;
84435c4bbdfSmrg        }
84535c4bbdfSmrg        else {
84635c4bbdfSmrg            *outstr++ = *str++;
84735c4bbdfSmrg        }
84835c4bbdfSmrg    }
84935c4bbdfSmrg    *outstr++ = '\0';
85035c4bbdfSmrg    if (orig != name)
85135c4bbdfSmrg        free(orig);
85205b261ecSmrg    return name;
85305b261ecSmrg}
85405b261ecSmrg
85505b261ecSmrg/***====================================================================***/
85605b261ecSmrg
85705b261ecSmrgBool
85835c4bbdfSmrgXkbRF_GetComponents(XkbRF_RulesPtr rules,
85935c4bbdfSmrg                    XkbRF_VarDefsPtr defs, XkbComponentNamesPtr names)
86005b261ecSmrg{
86105b261ecSmrg    XkbRF_MultiDefsRec mdefs;
86205b261ecSmrg
86305b261ecSmrg    MakeMultiDefs(&mdefs, defs);
86405b261ecSmrg
86535c4bbdfSmrg    memset((char *) names, 0, sizeof(XkbComponentNamesRec));
86605b261ecSmrg    XkbRF_ClearPartialMatches(rules);
86705b261ecSmrg    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Normal);
86805b261ecSmrg    XkbRF_ApplyPartialMatches(rules, names);
86905b261ecSmrg    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Append);
87005b261ecSmrg    XkbRF_ApplyPartialMatches(rules, names);
87105b261ecSmrg    XkbRF_CheckApplyRules(rules, &mdefs, names, XkbRF_Option);
87235c4bbdfSmrg    XkbRF_ApplyPartialMatches(rules, names);
87305b261ecSmrg
87405b261ecSmrg    if (names->keycodes)
87535c4bbdfSmrg        names->keycodes = XkbRF_SubstituteVars(names->keycodes, &mdefs);
87635c4bbdfSmrg    if (names->symbols)
87735c4bbdfSmrg        names->symbols = XkbRF_SubstituteVars(names->symbols, &mdefs);
87805b261ecSmrg    if (names->types)
87935c4bbdfSmrg        names->types = XkbRF_SubstituteVars(names->types, &mdefs);
88005b261ecSmrg    if (names->compat)
88135c4bbdfSmrg        names->compat = XkbRF_SubstituteVars(names->compat, &mdefs);
88205b261ecSmrg    if (names->geometry)
88335c4bbdfSmrg        names->geometry = XkbRF_SubstituteVars(names->geometry, &mdefs);
88405b261ecSmrg
88505b261ecSmrg    FreeMultiDefs(&mdefs);
88605b261ecSmrg    return (names->keycodes && names->symbols && names->types &&
88735c4bbdfSmrg            names->compat && names->geometry);
88805b261ecSmrg}
88905b261ecSmrg
8906747b715Smrgstatic XkbRF_RulePtr
89135c4bbdfSmrgXkbRF_AddRule(XkbRF_RulesPtr rules)
89205b261ecSmrg{
89335c4bbdfSmrg    if (rules->sz_rules < 1) {
89435c4bbdfSmrg        rules->sz_rules = 16;
89535c4bbdfSmrg        rules->num_rules = 0;
89635c4bbdfSmrg        rules->rules = calloc(rules->sz_rules, sizeof(XkbRF_RuleRec));
89705b261ecSmrg    }
89835c4bbdfSmrg    else if (rules->num_rules >= rules->sz_rules) {
89935c4bbdfSmrg        rules->sz_rules *= 2;
90035c4bbdfSmrg        rules->rules = reallocarray(rules->rules,
90135c4bbdfSmrg                                    rules->sz_rules, sizeof(XkbRF_RuleRec));
90205b261ecSmrg    }
90305b261ecSmrg    if (!rules->rules) {
90435c4bbdfSmrg        rules->sz_rules = rules->num_rules = 0;
90535c4bbdfSmrg        DebugF("Allocation failure in XkbRF_AddRule\n");
90635c4bbdfSmrg        return NULL;
90705b261ecSmrg    }
90835c4bbdfSmrg    memset((char *) &rules->rules[rules->num_rules], 0, sizeof(XkbRF_RuleRec));
90905b261ecSmrg    return &rules->rules[rules->num_rules++];
91005b261ecSmrg}
91105b261ecSmrg
9126747b715Smrgstatic XkbRF_GroupPtr
91335c4bbdfSmrgXkbRF_AddGroup(XkbRF_RulesPtr rules)
91405b261ecSmrg{
91535c4bbdfSmrg    if (rules->sz_groups < 1) {
91635c4bbdfSmrg        rules->sz_groups = 16;
91735c4bbdfSmrg        rules->num_groups = 0;
91835c4bbdfSmrg        rules->groups = calloc(rules->sz_groups, sizeof(XkbRF_GroupRec));
91905b261ecSmrg    }
92005b261ecSmrg    else if (rules->num_groups >= rules->sz_groups) {
92135c4bbdfSmrg        rules->sz_groups *= 2;
92235c4bbdfSmrg        rules->groups = reallocarray(rules->groups,
92335c4bbdfSmrg                                     rules->sz_groups, sizeof(XkbRF_GroupRec));
92405b261ecSmrg    }
92505b261ecSmrg    if (!rules->groups) {
92635c4bbdfSmrg        rules->sz_groups = rules->num_groups = 0;
92735c4bbdfSmrg        return NULL;
92805b261ecSmrg    }
92905b261ecSmrg
93035c4bbdfSmrg    memset((char *) &rules->groups[rules->num_groups], 0,
93135c4bbdfSmrg           sizeof(XkbRF_GroupRec));
93205b261ecSmrg    return &rules->groups[rules->num_groups++];
93305b261ecSmrg}
93405b261ecSmrg
93505b261ecSmrgBool
93635c4bbdfSmrgXkbRF_LoadRules(FILE * file, XkbRF_RulesPtr rules)
93705b261ecSmrg{
93835c4bbdfSmrg    InputLine line;
93935c4bbdfSmrg    RemapSpec remap;
94035c4bbdfSmrg    XkbRF_RuleRec trule, *rule;
94135c4bbdfSmrg    XkbRF_GroupRec tgroup, *group;
94205b261ecSmrg
94305b261ecSmrg    if (!(rules && file))
94435c4bbdfSmrg        return FALSE;
94535c4bbdfSmrg    memset((char *) &remap, 0, sizeof(RemapSpec));
94635c4bbdfSmrg    memset((char *) &tgroup, 0, sizeof(XkbRF_GroupRec));
94705b261ecSmrg    InitInputLine(&line);
94835c4bbdfSmrg    while (GetInputLine(file, &line, TRUE)) {
94935c4bbdfSmrg        if (CheckLine(&line, &remap, &trule, &tgroup)) {
95005b261ecSmrg            if (tgroup.number) {
95135c4bbdfSmrg                if ((group = XkbRF_AddGroup(rules)) != NULL) {
95235c4bbdfSmrg                    *group = tgroup;
95335c4bbdfSmrg                    memset((char *) &tgroup, 0, sizeof(XkbRF_GroupRec));
95435c4bbdfSmrg                }
95535c4bbdfSmrg            }
95635c4bbdfSmrg            else {
95735c4bbdfSmrg                if ((rule = XkbRF_AddRule(rules)) != NULL) {
95835c4bbdfSmrg                    *rule = trule;
95935c4bbdfSmrg                    memset((char *) &trule, 0, sizeof(XkbRF_RuleRec));
96035c4bbdfSmrg                }
96135c4bbdfSmrg            }
96235c4bbdfSmrg        }
96335c4bbdfSmrg        line.num_line = 0;
96405b261ecSmrg    }
96505b261ecSmrg    FreeInputLine(&line);
9666747b715Smrg    return TRUE;
96705b261ecSmrg}
96805b261ecSmrg
96905b261ecSmrgBool
97035c4bbdfSmrgXkbRF_LoadRulesByName(char *base, char *locale, XkbRF_RulesPtr rules)
97105b261ecSmrg{
97235c4bbdfSmrg    FILE *file;
97335c4bbdfSmrg    char buf[PATH_MAX];
97435c4bbdfSmrg    Bool ok;
97505b261ecSmrg
97635c4bbdfSmrg    if ((!base) || (!rules))
97735c4bbdfSmrg        return FALSE;
97805b261ecSmrg    if (locale) {
97935c4bbdfSmrg        if (snprintf(buf, PATH_MAX, "%s-%s", base, locale) >= PATH_MAX)
98035c4bbdfSmrg            return FALSE;
98105b261ecSmrg    }
98205b261ecSmrg    else {
98335c4bbdfSmrg        if (strlen(base) + 1 > PATH_MAX)
98435c4bbdfSmrg            return FALSE;
98535c4bbdfSmrg        strcpy(buf, base);
98605b261ecSmrg    }
98705b261ecSmrg
98835c4bbdfSmrg    file = fopen(buf, "r");
98935c4bbdfSmrg    if ((!file) && (locale)) {  /* fallback if locale was specified */
99035c4bbdfSmrg        strcpy(buf, base);
99135c4bbdfSmrg        file = fopen(buf, "r");
99205b261ecSmrg    }
99305b261ecSmrg    if (!file)
99435c4bbdfSmrg        return FALSE;
99535c4bbdfSmrg    ok = XkbRF_LoadRules(file, rules);
99605b261ecSmrg    fclose(file);
99705b261ecSmrg    return ok;
99805b261ecSmrg}
99905b261ecSmrg
100005b261ecSmrg/***====================================================================***/
100105b261ecSmrg
100205b261ecSmrgXkbRF_RulesPtr
10036747b715SmrgXkbRF_Create(void)
100405b261ecSmrg{
100535c4bbdfSmrg    return calloc(1, sizeof(XkbRF_RulesRec));
100605b261ecSmrg}
100705b261ecSmrg
100805b261ecSmrg/***====================================================================***/
100905b261ecSmrg
101005b261ecSmrgvoid
101135c4bbdfSmrgXkbRF_Free(XkbRF_RulesPtr rules, Bool freeRules)
101205b261ecSmrg{
101335c4bbdfSmrg    int i;
101435c4bbdfSmrg    XkbRF_RulePtr rule;
101535c4bbdfSmrg    XkbRF_GroupPtr group;
101605b261ecSmrg
101705b261ecSmrg    if (!rules)
101835c4bbdfSmrg        return;
101905b261ecSmrg    if (rules->rules) {
102035c4bbdfSmrg        for (i = 0, rule = rules->rules; i < rules->num_rules; i++, rule++) {
102135c4bbdfSmrg            free((void *) rule->model);
102235c4bbdfSmrg            free((void *) rule->layout);
102335c4bbdfSmrg            free((void *) rule->variant);
102435c4bbdfSmrg            free((void *) rule->option);
102535c4bbdfSmrg            free((void *) rule->keycodes);
102635c4bbdfSmrg            free((void *) rule->symbols);
102735c4bbdfSmrg            free((void *) rule->types);
102835c4bbdfSmrg            free((void *) rule->compat);
102935c4bbdfSmrg            free((void *) rule->geometry);
103035c4bbdfSmrg            memset((char *) rule, 0, sizeof(XkbRF_RuleRec));
103135c4bbdfSmrg        }
103235c4bbdfSmrg        free(rules->rules);
103335c4bbdfSmrg        rules->num_rules = rules->sz_rules = 0;
103435c4bbdfSmrg        rules->rules = NULL;
103505b261ecSmrg    }
103605b261ecSmrg
103705b261ecSmrg    if (rules->groups) {
103835c4bbdfSmrg        for (i = 0, group = rules->groups; i < rules->num_groups; i++, group++) {
103935c4bbdfSmrg            free((void *) group->name);
104035c4bbdfSmrg            free(group->words);
104135c4bbdfSmrg        }
104235c4bbdfSmrg        free(rules->groups);
104335c4bbdfSmrg        rules->num_groups = 0;
104435c4bbdfSmrg        rules->groups = NULL;
104505b261ecSmrg    }
104605b261ecSmrg    if (freeRules)
104735c4bbdfSmrg        free(rules);
104805b261ecSmrg    return;
104905b261ecSmrg}
1050