* DEALINGS IN THE SOFTWARE.
*/
+#include "config.h"
+
#include "xkbcomp-priv.h"
#include "rules.h"
#include "include.h"
#include "scanner-utils.h"
+#define MAX_INCLUDE_DEPTH 5
+
/* Scanner / Lexer */
/* Values returned with some tokens, like yylval. */
TOK_BANG,
TOK_EQUALS,
TOK_STAR,
+ TOK_INCLUDE,
TOK_ERROR
};
{
skip_more_whitespace_and_comments:
/* Skip spaces. */
- while (chr(s, ' ') || chr(s, '\t'));
+ while (scanner_chr(s, ' ') || scanner_chr(s, '\t') || scanner_chr(s, '\r'));
/* Skip comments. */
- if (lit(s, "//")) {
- while (!eof(s) && !eol(s)) next(s);
+ if (scanner_lit(s, "//")) {
+ scanner_skip_to_eol(s);
}
/* New line. */
- if (eol(s)) {
- while (eol(s)) next(s);
+ if (scanner_eol(s)) {
+ while (scanner_eol(s)) scanner_next(s);
return TOK_END_OF_LINE;
}
/* Escaped line continuation. */
- if (chr(s, '\\')) {
- if (!eol(s)) {
+ if (scanner_chr(s, '\\')) {
+ /* Optional \r. */
+ scanner_chr(s, '\r');
+ if (!scanner_eol(s)) {
scanner_err(s, "illegal new line escape; must appear at end of line");
return TOK_ERROR;
}
- next(s);
+ scanner_next(s);
goto skip_more_whitespace_and_comments;
}
/* See if we're done. */
- if (eof(s)) return TOK_END_OF_FILE;
+ if (scanner_eof(s)) return TOK_END_OF_FILE;
/* New token. */
s->token_line = s->line;
s->token_column = s->column;
/* Operators and punctuation. */
- if (chr(s, '!')) return TOK_BANG;
- if (chr(s, '=')) return TOK_EQUALS;
- if (chr(s, '*')) return TOK_STAR;
+ if (scanner_chr(s, '!')) return TOK_BANG;
+ if (scanner_chr(s, '=')) return TOK_EQUALS;
+ if (scanner_chr(s, '*')) return TOK_STAR;
/* Group name. */
- if (chr(s, '$')) {
+ if (scanner_chr(s, '$')) {
val->string.start = s->s + s->pos;
val->string.len = 0;
- while (is_ident(peek(s))) {
- next(s);
+ while (is_ident(scanner_peek(s))) {
+ scanner_next(s);
val->string.len++;
}
if (val->string.len == 0) {
return TOK_GROUP_NAME;
}
+ /* Include statement. */
+ if (scanner_lit(s, "include"))
+ return TOK_INCLUDE;
+
/* Identifier. */
- if (is_ident(peek(s))) {
+ if (is_ident(scanner_peek(s))) {
val->string.start = s->s + s->pos;
val->string.len = 0;
- while (is_ident(peek(s))) {
- next(s);
+ while (is_ident(scanner_peek(s))) {
+ scanner_next(s);
val->string.len++;
}
return TOK_IDENTIFIER;
[KCCGST_GEOMETRY] = SVAL_LIT("geometry"),
};
+/* We use this to keep score whether an mlvo was matched or not; if not,
+ * we warn the user that his preference was ignored. */
+struct matched_sval {
+ struct sval sval;
+ bool matched;
+};
+typedef darray(struct matched_sval) darray_matched_sval;
+
/*
* A broken-down version of xkb_rule_names (without the rules,
* obviously).
*/
struct rule_names {
- struct sval model;
- darray_sval layouts;
- darray_sval variants;
- darray_sval options;
+ struct matched_sval model;
+ darray_matched_sval layouts;
+ darray_matched_sval variants;
+ darray_matched_sval options;
};
struct group {
/* Input.*/
struct rule_names rmlvo;
union lvalue val;
- struct scanner scanner;
darray(struct group) groups;
/* Current mapping. */
struct mapping mapping;
return v;
}
-static darray_sval
-split_comma_separated_string(const char *s)
+static darray_matched_sval
+split_comma_separated_mlvo(const char *s)
{
- darray_sval arr = darray_new();
+ darray_matched_sval arr = darray_new();
/*
* Make sure the array returned by this function always includes at
*/
if (!s) {
- struct sval val = { NULL, 0 };
+ struct matched_sval val = { .sval = { NULL, 0 } };
darray_append(arr, val);
return arr;
}
while (true) {
- struct sval val = { s, 0 };
- while (*s != '\0' && *s != ',') { s++; val.len++; }
- darray_append(arr, strip_spaces(val));
+ struct matched_sval val = { .sval = { s, 0 } };
+ while (*s != '\0' && *s != ',') { s++; val.sval.len++; }
+ val.sval = strip_spaces(val.sval);
+ darray_append(arr, val);
if (*s == '\0') break;
if (*s == ',') s++;
}
return NULL;
m->ctx = ctx;
- m->rmlvo.model.start = rmlvo->model;
- m->rmlvo.model.len = strlen_safe(rmlvo->model);
- m->rmlvo.layouts = split_comma_separated_string(rmlvo->layout);
- m->rmlvo.variants = split_comma_separated_string(rmlvo->variant);
- m->rmlvo.options = split_comma_separated_string(rmlvo->options);
+ m->rmlvo.model.sval.start = rmlvo->model;
+ m->rmlvo.model.sval.len = strlen_safe(rmlvo->model);
+ m->rmlvo.layouts = split_comma_separated_mlvo(rmlvo->layout);
+ m->rmlvo.variants = split_comma_separated_mlvo(rmlvo->variant);
+ m->rmlvo.options = split_comma_separated_mlvo(rmlvo->options);
return m;
}
darray_free(m->rmlvo.options);
darray_foreach(group, m->groups)
darray_free(group->elements);
+ for (int i = 0; i < _KCCGST_NUM_ENTRIES; i++)
+ darray_free(m->kccgst[i]);
darray_free(m->groups);
free(m);
}
-#define matcher_err(matcher, fmt, ...) \
- scanner_err(&(matcher)->scanner, fmt, ## __VA_ARGS__)
-
static void
matcher_group_start_new(struct matcher *m, struct sval name)
{
}
static void
-matcher_group_add_element(struct matcher *m, struct sval element)
+matcher_group_add_element(struct matcher *m, struct scanner *s,
+ struct sval element)
{
darray_append(darray_item(m->groups, darray_size(m->groups) - 1).elements,
element);
}
+static bool
+read_rules_file(struct xkb_context *ctx,
+ struct matcher *matcher,
+ unsigned include_depth,
+ FILE *file,
+ const char *path);
+
+static void
+matcher_include(struct matcher *m, struct scanner *parent_scanner,
+ unsigned include_depth,
+ struct sval inc)
+{
+ struct scanner s; /* parses the !include value */
+ FILE *file;
+
+ scanner_init(&s, m->ctx, inc.start, inc.len,
+ parent_scanner->file_name, NULL);
+ s.token_line = parent_scanner->token_line;
+ s.token_column = parent_scanner->token_column;
+ s.buf_pos = 0;
+
+ if (include_depth >= MAX_INCLUDE_DEPTH) {
+ scanner_err(&s, "maximum include depth (%d) exceeded; maybe there is an include loop?",
+ MAX_INCLUDE_DEPTH);
+ return;
+ }
+
+ while (!scanner_eof(&s) && !scanner_eol(&s)) {
+ if (scanner_chr(&s, '%')) {
+ if (scanner_chr(&s, '%')) {
+ scanner_buf_append(&s, '%');
+ }
+ else if (scanner_chr(&s, 'H')) {
+ const char *home = xkb_context_getenv(m->ctx, "HOME");
+ if (!home) {
+ scanner_err(&s, "%%H was used in an include statement, but the HOME environment variable is not set");
+ return;
+ }
+ if (!scanner_buf_appends(&s, home)) {
+ scanner_err(&s, "include path after expanding %%H is too long");
+ return;
+ }
+ }
+ else if (scanner_chr(&s, 'S')) {
+ const char *default_root = xkb_context_include_path_get_system_path(m->ctx);
+ if (!scanner_buf_appends(&s, default_root) || !scanner_buf_appends(&s, "/rules")) {
+ scanner_err(&s, "include path after expanding %%S is too long");
+ return;
+ }
+ }
+ else if (scanner_chr(&s, 'E')) {
+ const char *default_root = xkb_context_include_path_get_extra_path(m->ctx);
+ if (!scanner_buf_appends(&s, default_root) || !scanner_buf_appends(&s, "/rules")) {
+ scanner_err(&s, "include path after expanding %%E is too long");
+ return;
+ }
+ }
+ else {
+ scanner_err(&s, "unknown %% format (%c) in include statement", scanner_peek(&s));
+ return;
+ }
+ }
+ else {
+ scanner_buf_append(&s, scanner_next(&s));
+ }
+ }
+ if (!scanner_buf_append(&s, '\0')) {
+ scanner_err(&s, "include path is too long");
+ return;
+ }
+
+ file = fopen(s.buf, "rb");
+ if (file) {
+ bool ret = read_rules_file(m->ctx, m, include_depth + 1, file, s.buf);
+ if (!ret)
+ log_err(m->ctx, XKB_LOG_MESSAGE_NO_ID,
+ "No components returned from included XKB rules \"%s\"\n",
+ s.buf);
+ fclose(file);
+ } else {
+ log_err(m->ctx, XKB_LOG_MESSAGE_NO_ID,
+ "Failed to open included XKB rules \"%s\"\n",
+ s.buf);
+ }
+}
+
static void
matcher_mapping_start_new(struct matcher *m)
{
}
static void
-matcher_mapping_set_mlvo(struct matcher *m, struct sval ident)
+matcher_mapping_set_mlvo(struct matcher *m, struct scanner *s,
+ struct sval ident)
{
enum rules_mlvo mlvo;
struct sval mlvo_sval;
/* Not found. */
if (mlvo >= _MLVO_NUM_ENTRIES) {
- matcher_err(m, "invalid mapping: %.*s is not a valid value here; ignoring rule set",
+ scanner_err(s, "invalid mapping: %.*s is not a valid value here; ignoring rule set",
ident.len, ident.start);
m->mapping.skip = true;
return;
}
if (m->mapping.defined_mlvo_mask & (1u << mlvo)) {
- matcher_err(m, "invalid mapping: %.*s appears twice on the same line; ignoring rule set",
+ scanner_err(s, "invalid mapping: %.*s appears twice on the same line; ignoring rule set",
mlvo_sval.len, mlvo_sval.start);
m->mapping.skip = true;
return;
int consumed = extract_layout_index(ident.start + mlvo_sval.len,
ident.len - mlvo_sval.len, &idx);
if ((int) (ident.len - mlvo_sval.len) != consumed) {
- matcher_err(m, "invalid mapping: \"%.*s\" may only be followed by a valid group index; ignoring rule set",
+ scanner_err(s, "invalid mapping: \"%.*s\" may only be followed by a valid group index; ignoring rule set",
mlvo_sval.len, mlvo_sval.start);
m->mapping.skip = true;
return;
m->mapping.variant_idx = idx;
}
else {
- matcher_err(m, "invalid mapping: \"%.*s\" cannot be followed by a group index; ignoring rule set",
+ scanner_err(s, "invalid mapping: \"%.*s\" cannot be followed by a group index; ignoring rule set",
mlvo_sval.len, mlvo_sval.start);
m->mapping.skip = true;
return;
}
static void
-matcher_mapping_set_kccgst(struct matcher *m, struct sval ident)
+matcher_mapping_set_kccgst(struct matcher *m, struct scanner *s, struct sval ident)
{
enum rules_kccgst kccgst;
struct sval kccgst_sval;
/* Not found. */
if (kccgst >= _KCCGST_NUM_ENTRIES) {
- matcher_err(m, "invalid mapping: %.*s is not a valid value here; ignoring rule set",
+ scanner_err(s, "invalid mapping: %.*s is not a valid value here; ignoring rule set",
ident.len, ident.start);
m->mapping.skip = true;
return;
}
if (m->mapping.defined_kccgst_mask & (1u << kccgst)) {
- matcher_err(m, "invalid mapping: %.*s appears twice on the same line; ignoring rule set",
+ scanner_err(s, "invalid mapping: %.*s appears twice on the same line; ignoring rule set",
kccgst_sval.len, kccgst_sval.start);
m->mapping.skip = true;
return;
}
static void
-matcher_mapping_verify(struct matcher *m)
+matcher_mapping_verify(struct matcher *m, struct scanner *s)
{
if (m->mapping.num_mlvo == 0) {
- matcher_err(m, "invalid mapping: must have at least one value on the left hand side; ignoring rule set");
+ scanner_err(s, "invalid mapping: must have at least one value on the left hand side; ignoring rule set");
goto skip;
}
if (m->mapping.num_kccgst == 0) {
- matcher_err(m, "invalid mapping: must have at least one value on the right hand side; ignoring rule set");
+ scanner_err(s, "invalid mapping: must have at least one value on the right hand side; ignoring rule set");
goto skip;
}
}
static void
-matcher_rule_set_mlvo_common(struct matcher *m, struct sval ident,
+matcher_rule_set_mlvo_common(struct matcher *m, struct scanner *s,
+ struct sval ident,
enum mlvo_match_type match_type)
{
if (m->rule.num_mlvo_values + 1 > m->mapping.num_mlvo) {
- matcher_err(m, "invalid rule: has more values than the mapping line; ignoring rule");
+ scanner_err(s, "invalid rule: has more values than the mapping line; ignoring rule");
m->rule.skip = true;
return;
}
}
static void
-matcher_rule_set_mlvo_wildcard(struct matcher *m)
+matcher_rule_set_mlvo_wildcard(struct matcher *m, struct scanner *s)
{
struct sval dummy = { NULL, 0 };
- matcher_rule_set_mlvo_common(m, dummy, MLVO_MATCH_WILDCARD);
+ matcher_rule_set_mlvo_common(m, s, dummy, MLVO_MATCH_WILDCARD);
}
static void
-matcher_rule_set_mlvo_group(struct matcher *m, struct sval ident)
+matcher_rule_set_mlvo_group(struct matcher *m, struct scanner *s,
+ struct sval ident)
{
- matcher_rule_set_mlvo_common(m, ident, MLVO_MATCH_GROUP);
+ matcher_rule_set_mlvo_common(m, s, ident, MLVO_MATCH_GROUP);
}
static void
-matcher_rule_set_mlvo(struct matcher *m, struct sval ident)
+matcher_rule_set_mlvo(struct matcher *m, struct scanner *s,
+ struct sval ident)
{
- matcher_rule_set_mlvo_common(m, ident, MLVO_MATCH_NORMAL);
+ matcher_rule_set_mlvo_common(m, s, ident, MLVO_MATCH_NORMAL);
}
static void
-matcher_rule_set_kccgst(struct matcher *m, struct sval ident)
+matcher_rule_set_kccgst(struct matcher *m, struct scanner *s,
+ struct sval ident)
{
if (m->rule.num_kccgst_values + 1 > m->mapping.num_kccgst) {
- matcher_err(m, "invalid rule: has more values than the mapping line; ignoring rule");
+ scanner_err(s, "invalid rule: has more values than the mapping line; ignoring rule");
m->rule.skip = true;
return;
}
static bool
match_value(struct matcher *m, struct sval val, struct sval to,
- enum mlvo_match_type match_type)
+ enum mlvo_match_type match_type)
{
if (match_type == MLVO_MATCH_WILDCARD)
return true;
return svaleq(val, to);
}
+static bool
+match_value_and_mark(struct matcher *m, struct sval val,
+ struct matched_sval *to, enum mlvo_match_type match_type)
+{
+ bool matched = match_value(m, val, to->sval, match_type);
+ if (matched)
+ to->matched = true;
+ return matched;
+}
+
/*
* This function performs %-expansion on @value (see overview above),
* and appends the result to @to.
*/
static bool
-append_expanded_kccgst_value(struct matcher *m, darray_char *to,
- struct sval value)
+append_expanded_kccgst_value(struct matcher *m, struct scanner *s,
+ darray_char *to, struct sval value)
{
- const char *s = value.start;
+ const char *str = value.start;
darray_char expanded = darray_new();
char ch;
bool expanded_plus, to_plus;
enum rules_mlvo mlv;
xkb_layout_index_t idx;
char pfx, sfx;
- struct sval expanded_value;
+ struct matched_sval *expanded_value;
/* Check if that's a start of an expansion. */
- if (s[i] != '%') {
+ if (str[i] != '%') {
/* Just a normal character. */
- darray_appends_nullterminate(expanded, &s[i++], 1);
+ darray_appends_nullterminate(expanded, &str[i++], 1);
continue;
}
if (++i >= value.len) goto error;
pfx = sfx = 0;
/* Check for prefix. */
- if (s[i] == '(' || s[i] == '+' || s[i] == '|' ||
- s[i] == '_' || s[i] == '-') {
- pfx = s[i];
- if (s[i] == '(') sfx = ')';
+ if (str[i] == '(' || str[i] == '+' || str[i] == '|' ||
+ str[i] == '_' || str[i] == '-') {
+ pfx = str[i];
+ if (str[i] == '(') sfx = ')';
if (++i >= value.len) goto error;
}
/* Mandatory model/layout/variant specifier. */
- switch (s[i++]) {
+ switch (str[i++]) {
case 'm': mlv = MLVO_MODEL; break;
case 'l': mlv = MLVO_LAYOUT; break;
case 'v': mlv = MLVO_VARIANT; break;
/* Check for index. */
idx = XKB_LAYOUT_INVALID;
- if (i < value.len && s[i] == '[') {
+ if (i < value.len && str[i] == '[') {
int consumed;
if (mlv != MLVO_LAYOUT && mlv != MLVO_VARIANT) {
- matcher_err(m, "invalid index in %%-expansion; may only index layout or variant");
+ scanner_err(s, "invalid index in %%-expansion; may only index layout or variant");
goto error;
}
- consumed = extract_layout_index(s + i, value.len - i, &idx);
+ consumed = extract_layout_index(str + i, value.len - i, &idx);
if (consumed == -1) goto error;
i += consumed;
}
/* Check for suffix, if there supposed to be one. */
if (sfx != 0) {
if (i >= value.len) goto error;
- if (s[i++] != sfx) goto error;
+ if (str[i++] != sfx) goto error;
}
/* Get the expanded value. */
- expanded_value.len = 0;
+ expanded_value = NULL;
if (mlv == MLVO_LAYOUT) {
if (idx != XKB_LAYOUT_INVALID &&
idx < darray_size(m->rmlvo.layouts) &&
darray_size(m->rmlvo.layouts) > 1)
- expanded_value = darray_item(m->rmlvo.layouts, idx);
+ expanded_value = &darray_item(m->rmlvo.layouts, idx);
else if (idx == XKB_LAYOUT_INVALID &&
darray_size(m->rmlvo.layouts) == 1)
- expanded_value = darray_item(m->rmlvo.layouts, 0);
+ expanded_value = &darray_item(m->rmlvo.layouts, 0);
}
else if (mlv == MLVO_VARIANT) {
if (idx != XKB_LAYOUT_INVALID &&
idx < darray_size(m->rmlvo.variants) &&
darray_size(m->rmlvo.variants) > 1)
- expanded_value = darray_item(m->rmlvo.variants, idx);
+ expanded_value = &darray_item(m->rmlvo.variants, idx);
else if (idx == XKB_LAYOUT_INVALID &&
darray_size(m->rmlvo.variants) == 1)
- expanded_value = darray_item(m->rmlvo.variants, 0);
+ expanded_value = &darray_item(m->rmlvo.variants, 0);
}
else if (mlv == MLVO_MODEL) {
- expanded_value = m->rmlvo.model;
+ expanded_value = &m->rmlvo.model;
}
/* If we didn't get one, skip silently. */
- if (expanded_value.len <= 0)
+ if (!expanded_value || expanded_value->sval.len == 0)
continue;
if (pfx != 0)
darray_appends_nullterminate(expanded, &pfx, 1);
darray_appends_nullterminate(expanded,
- expanded_value.start, expanded_value.len);
+ expanded_value->sval.start,
+ expanded_value->sval.len);
if (sfx != 0)
darray_appends_nullterminate(expanded, &sfx, 1);
+ expanded_value->matched = true;
}
/*
error:
darray_free(expanded);
- matcher_err(m, "invalid %%-expansion in value; not used");
+ scanner_err(s, "invalid %%-expansion in value; not used");
return false;
}
static void
-matcher_rule_verify(struct matcher *m)
+matcher_rule_verify(struct matcher *m, struct scanner *s)
{
if (m->rule.num_mlvo_values != m->mapping.num_mlvo ||
m->rule.num_kccgst_values != m->mapping.num_kccgst) {
- matcher_err(m, "invalid rule: must have same number of values as mapping line; ignoring rule");
+ scanner_err(s, "invalid rule: must have same number of values as mapping line; ignoring rule");
m->rule.skip = true;
}
}
static void
-matcher_rule_apply_if_matches(struct matcher *m)
+matcher_rule_apply_if_matches(struct matcher *m, struct scanner *s)
{
for (unsigned i = 0; i < m->mapping.num_mlvo; i++) {
enum rules_mlvo mlvo = m->mapping.mlvo_at_pos[i];
struct sval value = m->rule.mlvo_value_at_pos[i];
enum mlvo_match_type match_type = m->rule.match_type_at_pos[i];
+ struct matched_sval *to;
bool matched = false;
if (mlvo == MLVO_MODEL) {
- matched = match_value(m, value, m->rmlvo.model, match_type);
+ to = &m->rmlvo.model;
+ matched = match_value_and_mark(m, value, to, match_type);
}
else if (mlvo == MLVO_LAYOUT) {
xkb_layout_index_t idx = m->mapping.layout_idx;
idx = (idx == XKB_LAYOUT_INVALID ? 0 : idx);
- matched = match_value(m, value,
- darray_item(m->rmlvo.layouts, idx),
- match_type);
+ to = &darray_item(m->rmlvo.layouts, idx);
+ matched = match_value_and_mark(m, value, to, match_type);
}
else if (mlvo == MLVO_VARIANT) {
xkb_layout_index_t idx = m->mapping.layout_idx;
idx = (idx == XKB_LAYOUT_INVALID ? 0 : idx);
- matched = match_value(m, value,
- darray_item(m->rmlvo.variants, idx),
- match_type);
+ to = &darray_item(m->rmlvo.variants, idx);
+ matched = match_value_and_mark(m, value, to, match_type);
}
else if (mlvo == MLVO_OPTION) {
- struct sval *option;
- darray_foreach(option, m->rmlvo.options) {
- matched = match_value(m, value, *option, match_type);
+ darray_foreach(to, m->rmlvo.options) {
+ matched = match_value_and_mark(m, value, to, match_type);
if (matched)
break;
}
for (unsigned i = 0; i < m->mapping.num_kccgst; i++) {
enum rules_kccgst kccgst = m->mapping.kccgst_at_pos[i];
struct sval value = m->rule.kccgst_value_at_pos[i];
- append_expanded_kccgst_value(m, &m->kccgst[kccgst], value);
+ append_expanded_kccgst_value(m, s, &m->kccgst[kccgst], value);
}
/*
}
static enum rules_token
-gettok(struct matcher *m)
+gettok(struct matcher *m, struct scanner *s)
{
- return lex(&m->scanner, &m->val);
+ return lex(s, &m->val);
}
static bool
-matcher_match(struct matcher *m, const char *string, size_t len,
- const char *file_name, struct xkb_component_names *out)
+matcher_match(struct matcher *m, struct scanner *s,
+ unsigned include_depth,
+ const char *string, size_t len,
+ const char *file_name)
{
enum rules_token tok;
if (!m)
return false;
- scanner_init(&m->scanner, m->ctx, string, len, file_name);
-
initial:
- switch (tok = gettok(m)) {
+ switch (tok = gettok(m, s)) {
case TOK_BANG:
goto bang;
case TOK_END_OF_LINE:
}
bang:
- switch (tok = gettok(m)) {
+ switch (tok = gettok(m, s)) {
case TOK_GROUP_NAME:
matcher_group_start_new(m, m->val.string);
goto group_name;
+ case TOK_INCLUDE:
+ goto include_statement;
case TOK_IDENTIFIER:
matcher_mapping_start_new(m);
- matcher_mapping_set_mlvo(m, m->val.string);
+ matcher_mapping_set_mlvo(m, s, m->val.string);
goto mapping_mlvo;
default:
goto unexpected;
}
group_name:
- switch (tok = gettok(m)) {
+ switch (tok = gettok(m, s)) {
case TOK_EQUALS:
goto group_element;
default:
}
group_element:
- switch (tok = gettok(m)) {
+ switch (tok = gettok(m, s)) {
case TOK_IDENTIFIER:
- matcher_group_add_element(m, m->val.string);
+ matcher_group_add_element(m, s, m->val.string);
goto group_element;
case TOK_END_OF_LINE:
goto initial;
goto unexpected;
}
+include_statement:
+ switch (tok = gettok(m, s)) {
+ case TOK_IDENTIFIER:
+ matcher_include(m, s, include_depth, m->val.string);
+ goto initial;
+ default:
+ goto unexpected;
+ }
+
mapping_mlvo:
- switch (tok = gettok(m)) {
+ switch (tok = gettok(m, s)) {
case TOK_IDENTIFIER:
if (!m->mapping.skip)
- matcher_mapping_set_mlvo(m, m->val.string);
+ matcher_mapping_set_mlvo(m, s, m->val.string);
goto mapping_mlvo;
case TOK_EQUALS:
goto mapping_kccgst;
}
mapping_kccgst:
- switch (tok = gettok(m)) {
+ switch (tok = gettok(m, s)) {
case TOK_IDENTIFIER:
if (!m->mapping.skip)
- matcher_mapping_set_kccgst(m, m->val.string);
+ matcher_mapping_set_kccgst(m, s, m->val.string);
goto mapping_kccgst;
case TOK_END_OF_LINE:
if (!m->mapping.skip)
- matcher_mapping_verify(m);
+ matcher_mapping_verify(m, s);
goto rule_mlvo_first;
default:
goto unexpected;
}
rule_mlvo_first:
- switch (tok = gettok(m)) {
+ switch (tok = gettok(m, s)) {
case TOK_BANG:
goto bang;
case TOK_END_OF_LINE:
}
rule_mlvo:
- tok = gettok(m);
+ tok = gettok(m, s);
rule_mlvo_no_tok:
switch (tok) {
case TOK_IDENTIFIER:
if (!m->rule.skip)
- matcher_rule_set_mlvo(m, m->val.string);
+ matcher_rule_set_mlvo(m, s, m->val.string);
goto rule_mlvo;
case TOK_STAR:
if (!m->rule.skip)
- matcher_rule_set_mlvo_wildcard(m);
+ matcher_rule_set_mlvo_wildcard(m, s);
goto rule_mlvo;
case TOK_GROUP_NAME:
if (!m->rule.skip)
- matcher_rule_set_mlvo_group(m, m->val.string);
+ matcher_rule_set_mlvo_group(m, s, m->val.string);
goto rule_mlvo;
case TOK_EQUALS:
goto rule_kccgst;
}
rule_kccgst:
- switch (tok = gettok(m)) {
+ switch (tok = gettok(m, s)) {
case TOK_IDENTIFIER:
if (!m->rule.skip)
- matcher_rule_set_kccgst(m, m->val.string);
+ matcher_rule_set_kccgst(m, s, m->val.string);
goto rule_kccgst;
case TOK_END_OF_LINE:
if (!m->rule.skip)
- matcher_rule_verify(m);
+ matcher_rule_verify(m, s);
if (!m->rule.skip)
- matcher_rule_apply_if_matches(m);
+ matcher_rule_apply_if_matches(m, s);
goto rule_mlvo_first;
default:
goto unexpected;
}
finish:
- if (darray_empty(m->kccgst[KCCGST_KEYCODES]) ||
- darray_empty(m->kccgst[KCCGST_TYPES]) ||
- darray_empty(m->kccgst[KCCGST_COMPAT]) ||
- /* darray_empty(m->kccgst[KCCGST_GEOMETRY]) || */
- darray_empty(m->kccgst[KCCGST_SYMBOLS]))
- goto error;
-
- out->keycodes = darray_mem(m->kccgst[KCCGST_KEYCODES], 0);
- out->types = darray_mem(m->kccgst[KCCGST_TYPES], 0);
- out->compat = darray_mem(m->kccgst[KCCGST_COMPAT], 0);
- /* out->geometry = darray_mem(m->kccgst[KCCGST_GEOMETRY], 0); */
- darray_free(m->kccgst[KCCGST_GEOMETRY]);
- out->symbols = darray_mem(m->kccgst[KCCGST_SYMBOLS], 0);
-
return true;
state_error:
- matcher_err(m, "unexpected token");
+ scanner_err(s, "unexpected token");
error:
return false;
}
+static bool
+read_rules_file(struct xkb_context *ctx,
+ struct matcher *matcher,
+ unsigned include_depth,
+ FILE *file,
+ const char *path)
+{
+ bool ret = false;
+ char *string;
+ size_t size;
+ struct scanner scanner;
+
+ ret = map_file(file, &string, &size);
+ if (!ret) {
+ log_err(ctx, XKB_LOG_MESSAGE_NO_ID,
+ "Couldn't read rules file \"%s\": %s\n",
+ path, strerror(errno));
+ goto out;
+ }
+
+ scanner_init(&scanner, matcher->ctx, string, size, path, NULL);
+
+ ret = matcher_match(matcher, &scanner, include_depth, string, size, path);
+
+ unmap_file(string, size);
+out:
+ return ret;
+}
+
bool
xkb_components_from_rules(struct xkb_context *ctx,
const struct xkb_rule_names *rmlvo,
{
bool ret = false;
FILE *file;
- char *path;
- const char *string;
- size_t size;
- struct matcher *matcher;
+ char *path = NULL;
+ struct matcher *matcher = NULL;
+ struct matched_sval *mval;
+ unsigned int offset = 0;
- file = FindFileInXkbPath(ctx, rmlvo->rules, FILE_TYPE_RULES, &path);
+ file = FindFileInXkbPath(ctx, rmlvo->rules, FILE_TYPE_RULES, &path, &offset);
if (!file)
goto err_out;
- ret = map_file(file, &string, &size);
- if (!ret) {
- log_err(ctx, "Couldn't read rules file \"%s\": %s\n",
- path, strerror(errno));
- goto err_file;
+ matcher = matcher_new(ctx, rmlvo);
+
+ ret = read_rules_file(ctx, matcher, 0, file, path);
+ if (!ret ||
+ darray_empty(matcher->kccgst[KCCGST_KEYCODES]) ||
+ darray_empty(matcher->kccgst[KCCGST_TYPES]) ||
+ darray_empty(matcher->kccgst[KCCGST_COMPAT]) ||
+ /* darray_empty(matcher->kccgst[KCCGST_GEOMETRY]) || */
+ darray_empty(matcher->kccgst[KCCGST_SYMBOLS])) {
+ log_err(ctx, XKB_LOG_MESSAGE_NO_ID,
+ "No components returned from XKB rules \"%s\"\n", path);
+ ret = false;
+ goto err_out;
}
- matcher = matcher_new(ctx, rmlvo);
- ret = matcher_match(matcher, string, size, path, out);
- if (!ret)
- log_err(ctx, "No components returned from XKB rules \"%s\"\n", path);
- matcher_free(matcher);
+ darray_steal(matcher->kccgst[KCCGST_KEYCODES], &out->keycodes, NULL);
+ darray_steal(matcher->kccgst[KCCGST_TYPES], &out->types, NULL);
+ darray_steal(matcher->kccgst[KCCGST_COMPAT], &out->compat, NULL);
+ darray_steal(matcher->kccgst[KCCGST_SYMBOLS], &out->symbols, NULL);
+ darray_free(matcher->kccgst[KCCGST_GEOMETRY]);
+
+ mval = &matcher->rmlvo.model;
+ if (!mval->matched && mval->sval.len > 0)
+ log_err(matcher->ctx, XKB_LOG_MESSAGE_NO_ID,
+ "Unrecognized RMLVO model \"%.*s\" was ignored\n",
+ mval->sval.len, mval->sval.start);
+ darray_foreach(mval, matcher->rmlvo.layouts)
+ if (!mval->matched && mval->sval.len > 0)
+ log_err(matcher->ctx, XKB_LOG_MESSAGE_NO_ID,
+ "Unrecognized RMLVO layout \"%.*s\" was ignored\n",
+ mval->sval.len, mval->sval.start);
+ darray_foreach(mval, matcher->rmlvo.variants)
+ if (!mval->matched && mval->sval.len > 0)
+ log_err(matcher->ctx, XKB_LOG_MESSAGE_NO_ID,
+ "Unrecognized RMLVO variant \"%.*s\" was ignored\n",
+ mval->sval.len, mval->sval.start);
+ darray_foreach(mval, matcher->rmlvo.options)
+ if (!mval->matched && mval->sval.len > 0)
+ log_err(matcher->ctx, XKB_LOG_MESSAGE_NO_ID,
+ "Unrecognized RMLVO option \"%.*s\" was ignored\n",
+ mval->sval.len, mval->sval.start);
- unmap_file(string, size);
-err_file:
- free(path);
- fclose(file);
err_out:
+ if (file)
+ fclose(file);
+ matcher_free(matcher);
+ free(path);
return ret;
}