diff options
Diffstat (limited to 'src/3rdparty/xkbcommon/src/xkbcomp/rules.c')
-rw-r--r-- | src/3rdparty/xkbcommon/src/xkbcomp/rules.c | 259 |
1 files changed, 73 insertions, 186 deletions
diff --git a/src/3rdparty/xkbcommon/src/xkbcomp/rules.c b/src/3rdparty/xkbcommon/src/xkbcomp/rules.c index de82d96119..61799e7059 100644 --- a/src/3rdparty/xkbcommon/src/xkbcomp/rules.c +++ b/src/3rdparty/xkbcommon/src/xkbcomp/rules.c @@ -52,84 +52,6 @@ #include "include.h" #include "scanner-utils.h" -/* - * The rules file - * ============== - * The purpose of this file is to map between configuration values that - * are easy for a user to specify and understand, and the configuration - * values xkbcomp uses and understands. - * xkbcomp uses the xkb_component_names struct, which maps directly to - * include statements of the appropriate sections, called for short - * KcCGST (see keycodes.c, types.c, compat.c, symbols.c; geometry.c was - * removed). These are not really intuitive or straight-forward for - * the uninitiated. - * Instead, the user passes in a xkb_rule_names struct, which consists - * of the name of a rules file (in Linux this is usually "evdev"), a - * keyboard model (e.g. "pc105"), a set of layouts (which will end up - * in different groups, e.g. "us,fr"), variants (used to alter/augment - * the respective layout, e.g. "intl,dvorak"), and a set of options - * (used to tweak some general behavior of the keyboard, e.g. - * "ctrl:nocaps,compose:menu" to make the Caps Lock key act like Ctrl - * and the Menu key like Compose). We call these RMLVO. - * - * Format of the file - * ------------------ - * The file consists of rule sets, each consisting of rules (one per - * line), which match the MLVO values on the left hand side, and, if - * the values match to the values the user passed in, results in the - * values on the right hand side being added to the resulting KcCGST. - * Since some values are related and repeated often, it is possible - * to group them together and refer to them by a group name in the - * rules. - * Along with matching values by simple string equality, and for - * membership in a group defined previously, rules may also contain - * "wildcard" values - "*" - which always match. These usually appear - * near the end. - * - * Grammer - * ------- - * (It might be helpful to look at a file like rules/evdev along with - * this grammer. Comments, whitespace, etc. are not shown.) - * - * File ::= { "!" (Group | RuleSet) } - * - * Group ::= GroupName "=" { GroupElement } "\n" - * GroupName ::= "$"<ident> - * GroupElement ::= <ident> - * - * RuleSet ::= Mapping { Rule } - * - * Mapping ::= { Mlvo } "=" { Kccgst } "\n" - * Mlvo ::= "model" | "option" | ("layout" | "variant") [ Index ] - * Index ::= "[" 1..XKB_NUM_GROUPS "]" - * Kccgst ::= "keycodes" | "symbols" | "types" | "compat" | "geometry" - * - * Rule ::= { MlvoValue } "=" { KccgstValue } "\n" - * MlvoValue ::= "*" | GroupName | <ident> - * KccgstValue ::= <ident> - * - * Notes: - * - The order of values in a Rule must be the same as the Mapping it - * follows. The mapping line determines the meaning of the values in - * the rules which follow in the RuleSet. - * - If a Rule is matched, %-expansion is performed on the KccgstValue, - * as follows: - * %m, %l, %v: - * The model, layout or variant, if only one was given (e.g. - * %l for "us,il" is invalid). - * %l[1], %v[1]: - * Layout or variant for the specified group Index, if more than - * one was given (e.g. %l[1] for "us" is invalid). - * %+m, %+l, %+v, %+l[1], %+v[1] - * As above, but prefixed with '+'. Similarly, '|', '-', '_' may be - * used instead of '+'. - * %(m), %(l), %(l[1]), %(v), %(v[1]): - * As above, but prefixed by '(' and suffixed by ')'. - * In case the expansion is invalid, as described above, it is - * skipped (the rest of the string is still processed); this includes - * the prefix and suffix (that's why you shouldn't use e.g. "(%v[1])"). - */ - /* Scanner / Lexer */ /* Values returned with some tokens, like yylval. */ @@ -137,14 +59,6 @@ union lvalue { struct sval string; }; -/* - * Holds the location in the file of the last processed token, - * like yylloc. - */ -struct location { - int line, column; -}; - enum rules_token { TOK_END_OF_FILE = 0, TOK_END_OF_LINE, @@ -156,14 +70,6 @@ enum rules_token { TOK_ERROR }; -/* C99 is stupid. Just use the 1 variant when there are no args. */ -#define scanner_error1(scanner, loc, msg) \ - log_warn((scanner)->ctx, "rules/%s:%d:%d: %s\n", \ - (scanner)->file_name, (loc)->line, (loc)->column, msg) -#define scanner_error(scanner, loc, fmt, ...) \ - log_warn((scanner)->ctx, "rules/%s:%d:%d: " fmt "\n", \ - (scanner)->file_name, (loc)->line, (loc)->column, __VA_ARGS__) - static inline bool is_ident(char ch) { @@ -171,7 +77,7 @@ is_ident(char ch) } static enum rules_token -lex(struct scanner *s, union lvalue *val, struct location *loc) +lex(struct scanner *s, union lvalue *val) { skip_more_whitespace_and_comments: /* Skip spaces. */ @@ -191,8 +97,7 @@ skip_more_whitespace_and_comments: /* Escaped line continuation. */ if (chr(s, '\\')) { if (!eol(s)) { - scanner_error1(s, loc, - "illegal new line escape; must appear at end of line"); + scanner_err(s, "illegal new line escape; must appear at end of line"); return TOK_ERROR; } next(s); @@ -203,8 +108,8 @@ skip_more_whitespace_and_comments: if (eof(s)) return TOK_END_OF_FILE; /* New token. */ - loc->line = s->line; - loc->column = s->column; + s->token_line = s->line; + s->token_column = s->column; /* Operators and punctuation. */ if (chr(s, '!')) return TOK_BANG; @@ -220,8 +125,7 @@ skip_more_whitespace_and_comments: val->string.len++; } if (val->string.len == 0) { - scanner_error1(s, loc, - "unexpected character after \'$\'; expected name"); + scanner_err(s, "unexpected character after \'$\'; expected name"); return TOK_ERROR; } return TOK_GROUP_NAME; @@ -238,7 +142,7 @@ skip_more_whitespace_and_comments: return TOK_IDENTIFIER; } - scanner_error1(s, loc, "unrecognized token"); + scanner_err(s, "unrecognized token"); return TOK_ERROR; } @@ -330,7 +234,6 @@ struct matcher { struct xkb_context *ctx; /* Input.*/ struct rule_names rmlvo; - struct location loc; union lvalue val; struct scanner scanner; darray(struct group) groups; @@ -410,10 +313,8 @@ matcher_free(struct matcher *m) free(m); } -#define matcher_error1(matcher, msg) \ - scanner_error1(&(matcher)->scanner, &(matcher)->loc, msg) -#define matcher_error(matcher, fmt, ...) \ - scanner_error(&(matcher)->scanner, &(matcher)->loc, fmt, __VA_ARGS__) +#define matcher_err(matcher, fmt, ...) \ + scanner_err(&(matcher)->scanner, fmt, ## __VA_ARGS__) static void matcher_group_start_new(struct matcher *m, struct sval name) @@ -474,19 +375,15 @@ matcher_mapping_set_mlvo(struct matcher *m, struct sval ident) /* Not found. */ if (mlvo >= _MLVO_NUM_ENTRIES) { - matcher_error(m, - "invalid mapping: %.*s is not a valid value here; " - "ignoring rule set", - ident.len, ident.start); + matcher_err(m, "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 & (1 << mlvo)) { - matcher_error(m, - "invalid mapping: %.*s appears twice on the same line; " - "ignoring rule set", - mlvo_sval.len, mlvo_sval.start); + if (m->mapping.defined_mlvo_mask & (1u << mlvo)) { + matcher_err(m, "invalid mapping: %.*s appears twice on the same line; ignoring rule set", + mlvo_sval.len, mlvo_sval.start); m->mapping.skip = true; return; } @@ -497,10 +394,8 @@ matcher_mapping_set_mlvo(struct matcher *m, struct sval ident) 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_error(m, - "invalid mapping:\" %.*s\" may only be followed by a valid group index; " - "ignoring rule set", - mlvo_sval.len, mlvo_sval.start); + matcher_err(m, "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; } @@ -512,17 +407,15 @@ matcher_mapping_set_mlvo(struct matcher *m, struct sval ident) m->mapping.variant_idx = idx; } else { - matcher_error(m, - "invalid mapping: \"%.*s\" cannot be followed by a group index; " - "ignoring rule set", - mlvo_sval.len, mlvo_sval.start); + matcher_err(m, "invalid mapping: \"%.*s\" cannot be followed by a group index; ignoring rule set", + mlvo_sval.len, mlvo_sval.start); m->mapping.skip = true; return; } } m->mapping.mlvo_at_pos[m->mapping.num_mlvo] = mlvo; - m->mapping.defined_mlvo_mask |= 1 << mlvo; + m->mapping.defined_mlvo_mask |= 1u << mlvo; m->mapping.num_mlvo++; } @@ -541,25 +434,21 @@ matcher_mapping_set_kccgst(struct matcher *m, struct sval ident) /* Not found. */ if (kccgst >= _KCCGST_NUM_ENTRIES) { - matcher_error(m, - "invalid mapping: %.*s is not a valid value here; " - "ignoring rule set", - ident.len, ident.start); + matcher_err(m, "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 & (1 << kccgst)) { - matcher_error(m, - "invalid mapping: %.*s appears twice on the same line; " - "ignoring rule set", - kccgst_sval.len, kccgst_sval.start); + if (m->mapping.defined_kccgst_mask & (1u << kccgst)) { + matcher_err(m, "invalid mapping: %.*s appears twice on the same line; ignoring rule set", + kccgst_sval.len, kccgst_sval.start); m->mapping.skip = true; return; } m->mapping.kccgst_at_pos[m->mapping.num_kccgst] = kccgst; - m->mapping.defined_kccgst_mask |= 1 << kccgst; + m->mapping.defined_kccgst_mask |= 1u << kccgst; m->mapping.num_kccgst++; } @@ -567,16 +456,12 @@ static void matcher_mapping_verify(struct matcher *m) { if (m->mapping.num_mlvo == 0) { - matcher_error1(m, - "invalid mapping: must have at least one value on the left hand side; " - "ignoring rule set"); + matcher_err(m, "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_error1(m, - "invalid mapping: must have at least one value on the right hand side; " - "ignoring rule set"); + matcher_err(m, "invalid mapping: must have at least one value on the right hand side; ignoring rule set"); goto skip; } @@ -585,7 +470,7 @@ matcher_mapping_verify(struct matcher *m) * See the "Notes" section in the overview above. */ - if (m->mapping.defined_mlvo_mask & (1 << MLVO_LAYOUT)) { + if (m->mapping.defined_mlvo_mask & (1u << MLVO_LAYOUT)) { if (m->mapping.layout_idx == XKB_LAYOUT_INVALID) { if (darray_size(m->rmlvo.layouts) > 1) goto skip; @@ -597,7 +482,7 @@ matcher_mapping_verify(struct matcher *m) } } - if (m->mapping.defined_mlvo_mask & (1 << MLVO_VARIANT)) { + if (m->mapping.defined_mlvo_mask & (1u << MLVO_VARIANT)) { if (m->mapping.variant_idx == XKB_LAYOUT_INVALID) { if (darray_size(m->rmlvo.variants) > 1) goto skip; @@ -627,9 +512,7 @@ matcher_rule_set_mlvo_common(struct matcher *m, struct sval ident, enum mlvo_match_type match_type) { if (m->rule.num_mlvo_values + 1 > m->mapping.num_mlvo) { - matcher_error1(m, - "invalid rule: has more values than the mapping line; " - "ignoring rule"); + matcher_err(m, "invalid rule: has more values than the mapping line; ignoring rule"); m->rule.skip = true; return; } @@ -661,9 +544,7 @@ static void matcher_rule_set_kccgst(struct matcher *m, struct sval ident) { if (m->rule.num_kccgst_values + 1 > m->mapping.num_kccgst) { - matcher_error1(m, - "invalid rule: has more values than the mapping line; " - "ignoring rule"); + matcher_err(m, "invalid rule: has more values than the mapping line; ignoring rule"); m->rule.skip = true; return; } @@ -720,20 +601,10 @@ static bool append_expanded_kccgst_value(struct matcher *m, darray_char *to, struct sval value) { - const size_t original_size = darray_size(*to); const char *s = value.start; - - /* - * Appending bar to foo -> foo (not an error if this happens) - * Appending +bar to foo -> foo+bar - * Appending bar to +foo -> bar+foo - * Appending +bar to +foo -> +foo+bar - */ - if (!darray_empty(*to) && s[0] != '+' && s[0] != '|') { - if (darray_item(*to, 0) == '+' || darray_item(*to, 0) == '|') - darray_prepend_items_nullterminate(*to, value.start, value.len); - return true; - } + darray_char expanded = darray_new(); + char ch; + bool expanded_plus, to_plus; /* * Some ugly hand-lexing here, but going through the scanner is more @@ -743,12 +614,12 @@ append_expanded_kccgst_value(struct matcher *m, darray_char *to, enum rules_mlvo mlv; xkb_layout_index_t idx; char pfx, sfx; - struct sval expanded; + struct sval expanded_value; /* Check if that's a start of an expansion. */ if (s[i] != '%') { /* Just a normal character. */ - darray_append_items_nullterminate(*to, &s[i++], 1); + darray_appends_nullterminate(expanded, &s[i++], 1); continue; } if (++i >= value.len) goto error; @@ -777,9 +648,7 @@ append_expanded_kccgst_value(struct matcher *m, darray_char *to, int consumed; if (mlv != MLVO_LAYOUT && mlv != MLVO_VARIANT) { - matcher_error1(m, - "invalid index in %%-expansion; " - "may only index layout or variant"); + matcher_err(m, "invalid index in %%-expansion; may only index layout or variant"); goto error; } @@ -795,46 +664,65 @@ append_expanded_kccgst_value(struct matcher *m, darray_char *to, } /* Get the expanded value. */ - expanded.len = 0; + expanded_value.len = 0; if (mlv == MLVO_LAYOUT) { if (idx != XKB_LAYOUT_INVALID && idx < darray_size(m->rmlvo.layouts) && darray_size(m->rmlvo.layouts) > 1) - expanded = 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 = 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 = 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 = darray_item(m->rmlvo.variants, 0); + expanded_value = darray_item(m->rmlvo.variants, 0); } else if (mlv == MLVO_MODEL) { - expanded = m->rmlvo.model; + expanded_value = m->rmlvo.model; } /* If we didn't get one, skip silently. */ - if (expanded.len <= 0) + if (expanded_value.len <= 0) continue; if (pfx != 0) - darray_append_items_nullterminate(*to, &pfx, 1); - darray_append_items_nullterminate(*to, expanded.start, expanded.len); + darray_appends_nullterminate(expanded, &pfx, 1); + darray_appends_nullterminate(expanded, + expanded_value.start, expanded_value.len); if (sfx != 0) - darray_append_items_nullterminate(*to, &sfx, 1); + darray_appends_nullterminate(expanded, &sfx, 1); } + /* + * Appending bar to foo -> foo (not an error if this happens) + * Appending +bar to foo -> foo+bar + * Appending bar to +foo -> bar+foo + * Appending +bar to +foo -> +foo+bar + */ + + ch = (darray_empty(expanded) ? '\0' : darray_item(expanded, 0)); + expanded_plus = (ch == '+' || ch == '|'); + ch = (darray_empty(*to) ? '\0' : darray_item(*to, 0)); + to_plus = (ch == '+' || ch == '|'); + + if (expanded_plus || darray_empty(*to)) + darray_appends_nullterminate(*to, expanded.item, expanded.size); + else if (to_plus) + darray_prepends_nullterminate(*to, expanded.item, expanded.size); + + darray_free(expanded); return true; error: - matcher_error1(m, "invalid %%-expansion in value; not used"); - darray_resize(*to, original_size); + darray_free(expanded); + matcher_err(m, "invalid %%-expansion in value; not used"); return false; } @@ -843,9 +731,7 @@ matcher_rule_verify(struct matcher *m) { if (m->rule.num_mlvo_values != m->mapping.num_mlvo || m->rule.num_kccgst_values != m->mapping.num_kccgst) { - matcher_error1(m, - "invalid rule: must have same number of values as mapping line;" - "ignoring rule"); + matcher_err(m, "invalid rule: must have same number of values as mapping line; ignoring rule"); m->rule.skip = true; } } @@ -907,7 +793,7 @@ matcher_rule_apply_if_matches(struct matcher *m) static enum rules_token gettok(struct matcher *m) { - return lex(&m->scanner, &m->val, &m->loc); + return lex(&m->scanner, &m->val); } static bool @@ -1068,7 +954,7 @@ finish: return true; state_error: - matcher_error1(m, "unexpected token"); + matcher_err(m, "unexpected token"); error: return false; } @@ -1091,12 +977,13 @@ xkb_components_from_rules(struct xkb_context *ctx, ret = map_file(file, &string, &size); if (!ret) { - log_err(ctx, "Couldn't read rules file: %s\n", strerror(errno)); + log_err(ctx, "Couldn't read rules file \"%s\": %s\n", + path, strerror(errno)); goto err_file; } matcher = matcher_new(ctx, rmlvo); - ret = matcher_match(matcher, string, size, rmlvo->rules, out); + 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); |