diff --git a/doc/cool-uris.yaml b/doc/cool-uris.yaml index b739ee5..9fae6d1 100644 --- a/doc/cool-uris.yaml +++ b/doc/cool-uris.yaml @@ -7,6 +7,7 @@ dir_63ce773eee1f9b680e6e312b48cc99ca.html: [] dir_891596f32582d3133e8915e72908625f.html: [] dir_d44c64559bbebec7f509842c48db8b23.html: [] dir_e68e8157741866f444e17edd764ebbae.html: [] +error-index.html: [] files.html: [] functions.html: [] functions_func.html: [] diff --git a/doc/doxygen-extra.css b/doc/doxygen-extra.css index 104fa0b..569cd2e 100644 --- a/doc/doxygen-extra.css +++ b/doc/doxygen-extra.css @@ -31,3 +31,31 @@ a[href^="https://"]::after background-size: contain; display: inline-block; } + +/******************************************************************************* + * Error index + ******************************************************************************/ + +div.example-container { + display: flex; + flex-flow: row wrap; + justify-content: space-between; + gap: 1em; +} + +div.example { + flex-grow: 1; + overflow-x: auto; + margin-top: 1em; +} + +div.example-inner { + height: 100%; + display: flex; + flex-direction: column; +} + +div.example-title { + padding: 0 0 1em 0; + font-style: italic; +} diff --git a/doc/message-registry.md b/doc/message-registry.md new file mode 100644 index 0000000..69027be --- /dev/null +++ b/doc/message-registry.md @@ -0,0 +1,293 @@ +# Error index {#error-index} + + + +This page lists the warnings and errors generated by xkbcommon. +There are currently 20 entries. + +@todo The documentation of the log messages is a work in progress. + +## Index + +| Code | Identifier | Description | Type | +| --------- | ---------------------------- | ----------- | ---- | +| [XKB-034] | `malformed-number-literal` | Warn on malformed number literals | Error | +| [XKB-060] | `unsupported-modifier-mask` | Warn on unsupported modifier mask | Error | +| [XKB-107] | `unrecognized-keysym` | Warn on unrecognized keysyms | Warning | +| [XKB-183] | `cannot-infer-key-type` | Warn if no key type can be inferred | Warning | +| [XKB-237] | `unsupported-group-index` | Warn when a group index is not supported | Error | +| [XKB-286] | `undefined-key-type` | Warn if using an undefined key type | Warning | +| [XKB-305] | `non-base-group-name` | Warn if a group name was defined for group other than the first one | Warning | +| [XKB-312] | `unsupported-shift-level` | Warn when a shift level is not supported | Error | +| [XKB-461] | `conflicting-key-symbol` | Warn if there are conflicting keysyms while merging keys | Warning | +| [XKB-516] | `extra-symbols-ignored` | TODO: add description | Warning | +| [XKB-578] | `wrong-field-type` | Warn when a field has not the expected type | Error | +| [XKB-645] | `unknown-char-escape-sequence` | Warn on unknown escape sequence in string literal | Warning | +| [XKB-700] | `multiple-groups-at-once` | Warn if a key defines multiple groups at once | Warning | +| [XKB-769] | `invalid-syntax` | The syntax is invalid and the file cannot be parsed | Error | +| [XKB-770] | `undefined-keycode` | TODO: add description | Warning | +| [XKB-800] | `conflicting-modmap` | Warn if there are conflicting modmap definitions | Warning | +| [XKB-883] | `conflicting-key-action` | Warn if there are conflicting actions while merging keys | Warning | +| [XKB-893] | `conflicting-key-type` | Warn if there are conflicting key types while merging groups | Warning | +| [XKB-935] | `conflicting-key-fields` | Warn if there are conflicting fields while merging keys | Warning | +| [XKB-965] | `unresolved-keymap-symbol` | Warn if using a symbol not defined in the keymap | Warning | + +## Details + +### XKB-034 – Malformed number literal {#XKB-034} + +
+
Since
1.0.0
+
Type
Error
+
Summary
Warn on malformed number literals
+
+ +xkbcommon can parse the following number literal formats: + +- *decimal integer:* 1, 123, etc. +- *decimal floating-point number:* 1.23, etc. +- *hexadecimal integer:* prefixed with “0x”: 0x123, 0xff, 0xAB, etc. + + +### XKB-060 – Unsupported modifier mask {#XKB-060} + +
+
Since
1.0.0
+
Type
Error
+
Summary
Warn on unsupported modifier mask
+
+ +### XKB-107 – Unrecognized keysym {#XKB-107} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn on unrecognized keysyms
+
+ +xkbcommon replaces keysyms it does not recognize by the keysym `NoSymbol`. + +You may find the list of supported keysyms in +`include/xkbcommon/xkbcommon-keysyms.h`. + + +#### Examples + +
+ Unrecognized keysym “`coma`” + +**Error message:** + +``` +xkbcommon: WARNING: [XKB-107] de:31:20: unrecognized keysym "coma" +``` + +xkbcommon does not recognize the keysym “`coma`”. It is most probably +a typo for “comma”. +See: `XKB_KEY_comma` in `include/xkbcommon/xkbcommon-keysyms.h`. + +**Fix:** +
+
+
+
Before
+```c +key {[ coma, semicolon, periodcentered, multiply ]}; +``` +
+
+
+
+
After
+```c +key {[ comma, semicolon, periodcentered, multiply ]}; +``` +
+
+
+
+ +### XKB-183 – Cannot infer key type {#XKB-183} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if no key type can be inferred
+
+ +### XKB-237 – Unsupported group index {#XKB-237} + +
+
Since
1.0.0
+
Type
Error
+
Summary
Warn when a group index is not supported
+
+ +xkbcommon supports group index in the range (1..4). + + +### XKB-286 – Undefined key type {#XKB-286} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if using an undefined key type
+
+ +### XKB-305 – Non base group name {#XKB-305} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if a group name was defined for group other than the first one
+
+ +### XKB-312 – Unsupported shift level {#XKB-312} + +
+
Since
1.0.0
+
Type
Error
+
Summary
Warn when a shift level is not supported
+
+ +Shift levels are _one_-indexed. xkbcommon supports two formats of shift levels: +as numbers and as identifiers `LevelN`, where `N` is in the range (1..8). + + +### XKB-461 – Conflicting key symbol {#XKB-461} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if there are conflicting keysyms while merging keys
+
+ +### XKB-516 – Extra symbols ignored {#XKB-516} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
TODO: add description
+
+ +### XKB-578 – Wrong field type {#XKB-578} + +
+
Since
1.0.0
+
Type
Error
+
Summary
Warn when a field has not the expected type
+
+ +### XKB-645 – Unknown char escape sequence {#XKB-645} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn on unknown escape sequence in string literal
+
+ +xkbcommon support the following escape sequences in string literals: + +| Escape sequence | Corresponding character | +| --------------- | ----------------------------------- | +| `\b` | `U+0008` Backspace | +| `\t` | `U+0009` Character tabulation | +| `\n` | `U+000A` Line feed | +| `\v` | `U+000B` Vertical tabulation | +| `\f` | `U+000C` Form feed | +| `\r` | `U+000D` Carriage return | +| `\e` | `U+001B` Escape | +| `\\` | `U+005C` Backslash | +| `\NNN` | _Octal_ escape, from `\0` to `\777` | + + +### XKB-700 – Multiple groups at once {#XKB-700} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if a key defines multiple groups at once
+
+ +### XKB-769 – Invalid syntax {#XKB-769} + +
+
Since
1.0.0
+
Type
Error
+
Summary
The syntax is invalid and the file cannot be parsed
+
+ +### XKB-770 – Undefined keycode {#XKB-770} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
TODO: add description
+
+ +### XKB-800 – Conflicting modmap {#XKB-800} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if there are conflicting modmap definitions
+
+ +@todo detailed explanation and examples + + +### XKB-883 – Conflicting key action {#XKB-883} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if there are conflicting actions while merging keys
+
+ +### XKB-893 – Conflicting key type {#XKB-893} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if there are conflicting key types while merging groups
+
+ +### XKB-935 – Conflicting key fields {#XKB-935} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if there are conflicting fields while merging keys
+
+ +### XKB-965 – Unresolved keymap symbol {#XKB-965} + +
+
Since
1.0.0
+
Type
Warning
+
Summary
Warn if using a symbol not defined in the keymap
+
+ +[XKB-034]: @ref XKB-034 +[XKB-060]: @ref XKB-060 +[XKB-107]: @ref XKB-107 +[XKB-183]: @ref XKB-183 +[XKB-237]: @ref XKB-237 +[XKB-286]: @ref XKB-286 +[XKB-305]: @ref XKB-305 +[XKB-312]: @ref XKB-312 +[XKB-461]: @ref XKB-461 +[XKB-516]: @ref XKB-516 +[XKB-578]: @ref XKB-578 +[XKB-645]: @ref XKB-645 +[XKB-700]: @ref XKB-700 +[XKB-769]: @ref XKB-769 +[XKB-770]: @ref XKB-770 +[XKB-800]: @ref XKB-800 +[XKB-883]: @ref XKB-883 +[XKB-893]: @ref XKB-893 +[XKB-935]: @ref XKB-935 +[XKB-965]: @ref XKB-965 diff --git a/doc/message-registry.md.jinja b/doc/message-registry.md.jinja new file mode 100644 index 0000000..e1d40d7 --- /dev/null +++ b/doc/message-registry.md.jinja @@ -0,0 +1,74 @@ +# Error index { {#--#} #error-index} + +{# NOTE: Prevent Doxygen issue by writing the comment after the first header. #} + + +This page lists the warnings and errors generated by xkbcommon. +There are currently {{ entries|length }} entries. + +@todo The documentation of the log messages is a work in progress. + +## Index + +| Code | Identifier | Description | Type | +| --------- | ---------------------------- | ----------- | ---- | +{% for entry in entries %} +| [{{entry.message_code}}] | `{{entry.id}}` | {{entry.description|prepend_todo}} | {{entry.type|capitalize}} | +{% endfor %} + +## Details + +{% for entry in entries %} +### {{entry.message_code}} – {{entry.message_name}} { {#--#}#{{entry.message_code}}} + +
+{% if entry.removed %} +
Added in
{{entry.added}}
+
Removed in
{{entry.removed}}
+{% else %} +
Since
{{entry.added}}
+{% endif %} +
Type
{{entry.type|capitalize}}
+
Summary
{{entry.description|prepend_todo}}
+
+ +{% if entry.details %} +{{entry.details}} + +{% endif %} +{% if entry.examples %} +#### Examples + +{% for example in entry.examples %} +
+ {{example.name}} + +{{example.description}} +{% if example.before %} +**Fix:** +
+
+
+
Before
+{{example.before-}} +
+
+
+
+
After
+{{example.after-}} +
+
+
+{% endif %} +
+ +{% endfor %} +{% endif %} +{% endfor %} +{% for entry in entries %} +[{{entry.message_code}}]: @ref {{entry.message_code}} +{% endfor %} diff --git a/doc/message-registry.yaml b/doc/message-registry.yaml new file mode 100644 index 0000000..fea4658 --- /dev/null +++ b/doc/message-registry.yaml @@ -0,0 +1,176 @@ +# Guidelines: +# • A message code must always have the same meaning forever. +# • Codes may be retired or introduced in new releases. In order to avoid +# clashes, retired codes must not be deleted. +# • Codes should not themselves reflect classification, e.g. a range for parse +# errors and a range for each keymap component. +# • Codes should not be assigned sequentially because it is misleading. +# • Codes must be in the range 1..999. This range may be extended once every +# code has be assigned. +# +# See the following guidelines for futher details on good practices: +# https://github.com/haskellfoundation/error-message-index/blob/main/tool-developers.md#code-assignment-recommendations + +# NOTE: Field “added: ALWAYS” means that the precise version is unknown and +# anterior to the introduction of the message registry. It will be replaced by +# the default version 1.0.0 in the generated documentation. While this is deemed +# good enough to avoid spelunking commit history, a more precise version would +# be welcome. + +# TODO: fix missing detailed description, examples, resolution + +- id: "malformed-number-literal" + code: 34 + added: ALWAYS + type: error + description: "Warn on malformed number literals" + details: | + xkbcommon can parse the following number literal formats: + + - *decimal integer:* 1, 123, etc. + - *decimal floating-point number:* 1.23, etc. + - *hexadecimal integer:* prefixed with “0x”: 0x123, 0xff, 0xAB, etc. +- id: "unsupported-modifier-mask" + code: 60 + added: ALWAYS + type: error + description: "Warn on unsupported modifier mask" +- id: "unrecognized-keysym" + code: 107 + added: ALWAYS + type: warning + description: "Warn on unrecognized keysyms" + details: | + xkbcommon replaces keysyms it does not recognize by the keysym `NoSymbol`. + + You may find the list of supported keysyms in + `include/xkbcommon/xkbcommon-keysyms.h`. + examples: + - name: Unrecognized keysym “`coma`” + description: | + **Error message:** + + ``` + xkbcommon: WARNING: [XKB-107] de:31:20: unrecognized keysym "coma" + ``` + + xkbcommon does not recognize the keysym “`coma`”. It is most probably + a typo for “comma”. + See: `XKB_KEY_comma` in `include/xkbcommon/xkbcommon-keysyms.h`. + before: | + ```c + key {[ coma, semicolon, periodcentered, multiply ]}; + ``` + after: | + ```c + key {[ comma, semicolon, periodcentered, multiply ]}; + ``` +- id: "cannot-infer-key-type" + code: 183 + added: ALWAYS + type: warning + description: "Warn if no key type can be inferred" +- id: "unsupported-group-index" + code: 237 + added: ALWAYS + type: error + description: "Warn when a group index is not supported" + details: | + xkbcommon supports group index in the range (1..{{XKB_MAX_GROUPS}}). +- id: "undefined-key-type" + code: 286 + added: ALWAYS + type: warning + description: "Warn if using an undefined key type" +- id: "non-base-group-name" + code: 305 + added: ALWAYS + type: warning + description: "Warn if a group name was defined for group other than the first one" +- id: "unsupported-shift-level" + code: 312 + added: ALWAYS + type: error + description: "Warn when a shift level is not supported" + details: | + Shift levels are _one_-indexed. xkbcommon supports two formats of shift levels: + as numbers and as identifiers `LevelN`, where `N` is in the range (1..8). +- id: "conflicting-key-symbol" + code: 461 + added: ALWAYS + type: warning + description: "Warn if there are conflicting keysyms while merging keys" +- id: "extra-symbols-ignored" + code: 516 + added: ALWAYS + type: warning + description: "TODO: add description" +- id: "wrong-field-type" + code: 578 + added: ALWAYS + type: error + description: "Warn when a field has not the expected type" +- id: "unknown-char-escape-sequence" + code: 645 + added: ALWAYS + type: warning + description: "Warn on unknown escape sequence in string literal" + details: | + xkbcommon support the following escape sequences in string literals: + + | Escape sequence | Corresponding character | + | --------------- | ----------------------------------- | + | `\b` | `U+0008` Backspace | + | `\t` | `U+0009` Character tabulation | + | `\n` | `U+000A` Line feed | + | `\v` | `U+000B` Vertical tabulation | + | `\f` | `U+000C` Form feed | + | `\r` | `U+000D` Carriage return | + | `\e` | `U+001B` Escape | + | `\\` | `U+005C` Backslash | + | `\NNN` | _Octal_ escape, from `\0` to `\777` | +- id: "multiple-groups-at-once" + code: 700 + added: ALWAYS + type: warning + description: "Warn if a key defines multiple groups at once" +- id: "invalid-syntax" + code: 769 + added: ALWAYS + type: error + description: "The syntax is invalid and the file cannot be parsed" +- id: "undefined-keycode" + code: 770 + added: ALWAYS + type: warning + description: "TODO: add description" +- id: "conflicting-modmap" + code: 800 + added: ALWAYS + type: warning + description: "Warn if there are conflicting modmap definitions" + details: | + @todo detailed explanation and examples +- id: "conflicting-key-action" + code: 883 + added: ALWAYS + type: warning + description: "Warn if there are conflicting actions while merging keys" +- id: "conflicting-key-type" + code: 893 + added: ALWAYS + type: warning + description: "Warn if there are conflicting key types while merging groups" +- id: "conflicting-key-fields" + code: 935 + added: ALWAYS + type: warning + description: "Warn if there are conflicting fields while merging keys" +- id: "unresolved-keymap-symbol" + code: 965 + added: ALWAYS + type: warning + description: "Warn if using a symbol not defined in the keymap" + +# TODO: deprecated keysym +# TODO: unicode keysym when named and recommended keysym exists diff --git a/meson.build b/meson.build index 0d6c8ce..f37d416 100644 --- a/meson.build +++ b/meson.build @@ -221,6 +221,7 @@ libxkbcommon_sources = [ 'src/keymap.c', 'src/keymap.h', 'src/keymap-priv.c', + 'src/messages-codes.h', 'src/scanner-utils.h', 'src/state.c', 'src/text.c', @@ -816,6 +817,7 @@ You can disable the documentation with -Denable-docs=false.''') 'doc/user-configuration.md', 'doc/rules-format.md', 'doc/keymap-format-text-v1.md', + 'doc/message-registry.md', 'include/xkbcommon/xkbcommon.h', 'include/xkbcommon/xkbcommon-compose.h', 'include/xkbcommon/xkbcommon-keysyms.h', diff --git a/scripts/update-message-registry.py b/scripts/update-message-registry.py new file mode 100755 index 0000000..785f209 --- /dev/null +++ b/scripts/update-message-registry.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +from dataclasses import astuple, dataclass +from pathlib import Path +import re +from typing import Callable, Generic, Sequence, TypeVar + +import jinja2 +import yaml + + +@dataclass(order=True) +class Version: + """A semantic version number: MAJOR.MINOR.PATCH.""" + + UNKNOWN_VERSION = "ALWAYS" + DEFAULT_VERSION = "1.0.0" + + major: int + minor: int + patch: int = 0 + + def __str__(self): + return ".".join(map(str, astuple(self))) + + @classmethod + def parse(cls, raw_version: str) -> Version: + if raw_version == cls.UNKNOWN_VERSION: + raw_version = cls.DEFAULT_VERSION + version = raw_version.split(".") + assert 2 <= len(version) <= 3 and all( + n.isdecimal() for n in version + ), raw_version + return Version(*map(int, version)) + + +@dataclass +class Example: + """An example in a message entry.""" + + name: str + description: str + before: str | None + after: str | None + + @classmethod + def parse(cls, entry) -> Example: + name = entry.get("name") + assert name, entry + + description = entry.get("description") + assert description + + before = entry.get("before") + after = entry.get("after") + # Either none or both of them + assert not (bool(before) ^ bool(after)) + + return Example(name=name, description=description, before=before, after=after) + + +@dataclass +class Entry: + """An xkbcommon message entry in the message registry""" + + VALID_TYPES = ("warning", "error") + + code: int + """A unique strictly positive integer identifier""" + id: str + """A unique short human-readable string identifier""" + type: str + """Log level of the message""" + description: str + """A short description of the meaning of the message""" + details: str + """A long description of the meaning of the message""" + added: Version + """Version of xkbcommon the message has been added""" + removed: Version | None + """Version of xkbcommon the message has been removed""" + examples: tuple[Example, ...] + """ + Optional examples of situations in which the message occurs. + If the message is an error or a warning, also provide hints on how to fix it. + """ + + @classmethod + def parse(cls, entry) -> Entry: + code = entry.get("code") + assert code is not None and isinstance(code, int) and code > 0, entry + + id = entry.get("id") + assert id is not None, entry + + type_ = entry.get("type") + assert type_ in cls.VALID_TYPES, entry + + description = entry.get("description") + assert description is not None, entry + + details = entry.get("details", "") + + raw_added = entry.get("added", "") + assert raw_added, entry + + added = Version.parse(raw_added) + assert added, entry + + if removed := entry.get("removed"): + removed = Version.parse(removed) + assert added < removed, entry + + if examples := entry.get("examples", ()): + examples = tuple(map(Example.parse, examples)) + + return Entry( + code=code, + id=id, + type=type_, + description=description, + added=added, + removed=removed, + details=details, + examples=examples, + ) + + @property + def message_code(self) -> str: + """Format the message code for display""" + return f"XKB-{self.code:0>3}" + + @property + def message_code_constant(self: Entry) -> str: + """Returns the C enumeration member denoting the message code""" + id = self.id.replace("-", "_").upper() + return f"XKB_{self.type.upper()}_{id}" + + @property + def message_name(self: Entry): + """Format the message string identifier for display""" + return self.id.replace("-", " ").capitalize() + + +def prepend_todo(text: str) -> str: + if text.startswith("TODO"): + return f"""{text[:5]}{text[5:]}""" + else: + return text + + +def load_message_registry( + env: jinja2.Environment, constants: dict[str, int], path: Path +) -> Sequence[Entry]: + # Load the message registry YAML file as a Jinja2 template + registry_template = env.get_template(str(path)) + + # Load message registry + message_registry = sorted( + map(Entry.parse, yaml.safe_load(registry_template.render(constants))), + key=lambda e: e.code, + ) + + # Check message codes and identifiers are unique + codes: set[int] = set() + identifiers: set[str] = set() + for n, entry in enumerate(message_registry): + if entry.code in codes: + raise ValueError("Duplicated code in entry #{n}: {entry.code}") + if entry.id in identifiers: + raise ValueError("Duplicated identifier in entry #{n}: {entry.id}") + codes.add(entry.code) + identifiers.add(entry.id) + + return message_registry + + +def generate( + registry: Sequence[Entry], + env: jinja2.Environment, + root: Path, + file: Path, + skip_removed: bool = False, +): + """Generate a file from its Jinja2 template and the message registry""" + template_path = file.with_suffix(f"{file.suffix}.jinja") + template = env.get_template(str(template_path)) + path = root / file + script = Path(__file__).name + with path.open("wt", encoding="utf-8") as fd: + entries = ( + tuple(filter(lambda e: e.removed is None, registry)) + if skip_removed + else registry + ) + fd.writelines(template.generate(entries=entries, script=script)) + + +T = TypeVar("T") + + +@dataclass +class Constant(Generic[T]): + name: str + pattern: re.Pattern + conversion: Callable[[str], T] + + +def read_constants(path: Path, patterns: Sequence[Constant[T]]) -> dict[str, T]: + constants: dict[str, T] = {} + patternsʹ = list(patterns) + with path.open("rt", encoding="utf-8") as fd: + for line in fd: + for k, constant in enumerate(patternsʹ): + if m := constant.pattern.match(line): + constants[constant.name] = constant.conversion(m.group(1)) + del patternsʹ[k] + continue # Expect only one match per line + if not patternsʹ: + # No more pattern to match + break + for constant in patternsʹ: + print(f"ERROR: could not find constant: {constant.name}.") + if patternsʹ: + raise ValueError("Some constants were not found.") + return constants + + +# Root of the project +ROOT = Path(__file__).parent.parent + +# Parse commands +parser = argparse.ArgumentParser(description="Generate files from the message registry") +parser.add_argument( + "--root", + type=Path, + default=ROOT, + help="Path to the root of the project (default: %(default)s)", +) + +args = parser.parse_args() + +# Read some constants from libxkbcommon that we need +constants = read_constants( + Path(__file__).parent.parent / "src" / "keymap.h", + (Constant("XKB_MAX_GROUPS", re.compile("^#define\s+XKB_MAX_GROUPS\s+(\d+)"), int),), +) + +# Configure Jinja +template_loader = jinja2.FileSystemLoader(args.root, encoding="utf-8") +jinja_env = jinja2.Environment( + loader=template_loader, + keep_trailing_newline=True, + trim_blocks=True, + lstrip_blocks=True, +) +jinja_env.filters["prepend_todo"] = prepend_todo + +# Load message registry +message_registry = load_message_registry( + jinja_env, constants, Path("doc/message-registry.yaml") +) + +# Generate the files +generate( + message_registry, + jinja_env, + args.root, + Path("src/messages-codes.h"), + skip_removed=True, +) +generate(message_registry, jinja_env, args.root, Path("doc/message-registry.md")) diff --git a/src/context.h b/src/context.h index 488bfad..d5fa117 100644 --- a/src/context.h +++ b/src/context.h @@ -27,6 +27,7 @@ #define CONTEXT_H #include "atom.h" +#include "messages-codes.h" struct xkb_context { int refcnt; @@ -114,16 +115,31 @@ xkb_context_sanitize_rule_names(struct xkb_context *ctx, * format is supplied without arguments. Not supplying it would still * result in an error, though. */ +#define xkb_log_with_code(ctx, level, verbosity, msg_id, fmt, ...) \ + xkb_log(ctx, level, verbosity, "[XKB-%03d] " fmt, \ + msg_id, ##__VA_ARGS__) +#define log_dbg_with_code(ctx, id, ...) \ + xkb_log_with_code((ctx), XKB_LOG_LEVEL_DEBUG, 0, (id), __VA_ARGS__) #define log_dbg(ctx, ...) \ xkb_log((ctx), XKB_LOG_LEVEL_DEBUG, 0, __VA_ARGS__) +#define log_info_with_code(ctx, id, ...) \ + xkb_log_with_code((ctx), XKB_LOG_LEVEL_INFO, 0, (id), __VA_ARGS__) #define log_info(ctx, ...) \ xkb_log((ctx), XKB_LOG_LEVEL_INFO, 0, __VA_ARGS__) +#define log_warn_with_code(ctx, id, ...) \ + xkb_log_with_code((ctx), XKB_LOG_LEVEL_WARNING, 0, (id), __VA_ARGS__) #define log_warn(ctx, ...) \ - xkb_log((ctx), XKB_LOG_LEVEL_WARNING, 0, __VA_ARGS__) + xkb_log((ctx), XKB_LOG_LEVEL_WARNING, 0, __VA_ARGS__) +#define log_err_with_code(ctx, id, ...) \ + xkb_log_with_code((ctx), XKB_LOG_LEVEL_ERROR, 0, (id), __VA_ARGS__) #define log_err(ctx, ...) \ - xkb_log((ctx), XKB_LOG_LEVEL_ERROR, 0, __VA_ARGS__) + xkb_log((ctx), XKB_LOG_LEVEL_ERROR, 0, __VA_ARGS__) +#define log_wsgo_with_code(ctx, id, ...) \ + xkb_log_with_code((ctx), XKB_LOG_LEVEL_CRITICAL, 0, (id), __VA_ARGS__) #define log_wsgo(ctx, ...) \ xkb_log((ctx), XKB_LOG_LEVEL_CRITICAL, 0, __VA_ARGS__) +#define log_vrb_with_code(ctx, vrb, id, ...) \ + xkb_log_with_code((ctx), XKB_LOG_LEVEL_WARNING, (vrb), (id), __VA_ARGS__) #define log_vrb(ctx, vrb, ...) \ xkb_log((ctx), XKB_LOG_LEVEL_WARNING, (vrb), __VA_ARGS__) diff --git a/src/messages-codes.h b/src/messages-codes.h new file mode 100644 index 0000000..64a6177 --- /dev/null +++ b/src/messages-codes.h @@ -0,0 +1,62 @@ +// NOTE: This file has been generated automatically by “update-message-registry.py”. +// Do not edit manually! + +#ifndef MESSAGES_H +#define MESSAGES_H + +#include + +/** + * @name Codes of the log messages + * + * @added 1.6.0 + * + */ +enum xkb_message_code { + _XKB_LOG_MESSAGE_MIN_CODE = 34, + /** Warn on malformed number literals */ + XKB_ERROR_MALFORMED_NUMBER_LITERAL = 34, + /** Warn on unsupported modifier mask */ + XKB_ERROR_UNSUPPORTED_MODIFIER_MASK = 60, + /** Warn on unrecognized keysyms */ + XKB_WARNING_UNRECOGNIZED_KEYSYM = 107, + /** Warn if no key type can be inferred */ + XKB_WARNING_CANNOT_INFER_KEY_TYPE = 183, + /** Warn when a group index is not supported */ + XKB_ERROR_UNSUPPORTED_GROUP_INDEX = 237, + /** Warn if using an undefined key type */ + XKB_WARNING_UNDEFINED_KEY_TYPE = 286, + /** Warn if a group name was defined for group other than the first one */ + XKB_WARNING_NON_BASE_GROUP_NAME = 305, + /** Warn when a shift level is not supported */ + XKB_ERROR_UNSUPPORTED_SHIFT_LEVEL = 312, + /** Warn if there are conflicting keysyms while merging keys */ + XKB_WARNING_CONFLICTING_KEY_SYMBOL = 461, + /** TODO: add description */ + XKB_WARNING_EXTRA_SYMBOLS_IGNORED = 516, + /** Warn when a field has not the expected type */ + XKB_ERROR_WRONG_FIELD_TYPE = 578, + /** Warn on unknown escape sequence in string literal */ + XKB_WARNING_UNKNOWN_CHAR_ESCAPE_SEQUENCE = 645, + /** Warn if a key defines multiple groups at once */ + XKB_WARNING_MULTIPLE_GROUPS_AT_ONCE = 700, + /** The syntax is invalid and the file cannot be parsed */ + XKB_ERROR_INVALID_SYNTAX = 769, + /** TODO: add description */ + XKB_WARNING_UNDEFINED_KEYCODE = 770, + /** Warn if there are conflicting modmap definitions */ + XKB_WARNING_CONFLICTING_MODMAP = 800, + /** Warn if there are conflicting actions while merging keys */ + XKB_WARNING_CONFLICTING_KEY_ACTION = 883, + /** Warn if there are conflicting key types while merging groups */ + XKB_WARNING_CONFLICTING_KEY_TYPE = 893, + /** Warn if there are conflicting fields while merging keys */ + XKB_WARNING_CONFLICTING_KEY_FIELDS = 935, + /** Warn if using a symbol not defined in the keymap */ + XKB_WARNING_UNRESOLVED_KEYMAP_SYMBOL = 965, + _XKB_LOG_MESSAGE_MAX_CODE = 965 +}; + +typedef uint32_t xkb_message_code_t; + +#endif diff --git a/src/messages-codes.h.jinja b/src/messages-codes.h.jinja new file mode 100644 index 0000000..2195af4 --- /dev/null +++ b/src/messages-codes.h.jinja @@ -0,0 +1,26 @@ +// NOTE: This file has been generated automatically by “{{script}}”. +// Do not edit manually! + +#ifndef MESSAGES_H +#define MESSAGES_H + +#include + +/** + * @name Codes of the log messages + * + * @added 1.6.0 + * + */ +enum xkb_message_code { + _XKB_LOG_MESSAGE_MIN_CODE = {{ entries[0].code }}, + {% for entry in entries %} + /** {{ entry.description }} */ + {{ entry.message_code_constant }} = {{ entry.code }}, + {% endfor %} + _XKB_LOG_MESSAGE_MAX_CODE = {{ entries[-1].code }} +}; + +typedef uint32_t xkb_message_code_t; + +#endif diff --git a/src/scanner-utils.h b/src/scanner-utils.h index cede0ff..f4c799e 100644 --- a/src/scanner-utils.h +++ b/src/scanner-utils.h @@ -57,15 +57,28 @@ struct scanner { void *priv; }; +#define scanner_log_with_code(scanner, level, log_msg_id, fmt, ...) \ + xkb_log_with_code((scanner)->ctx, (level), 0, log_msg_id, \ + "%s:%zu:%zu: " fmt "\n", \ + (scanner)->file_name, \ + (scanner)->token_line, \ + (scanner)->token_column, ##__VA_ARGS__) + #define scanner_log(scanner, level, fmt, ...) \ xkb_log((scanner)->ctx, (level), 0, \ "%s:%zu:%zu: " fmt "\n", \ - (scanner)->file_name, \ - (scanner)->token_line, (scanner)->token_column, ##__VA_ARGS__) + (scanner)->file_name, \ + (scanner)->token_line, (scanner)->token_column, ##__VA_ARGS__) + +#define scanner_err_with_code(scanner, id, fmt, ...) \ + scanner_log_with_code(scanner, XKB_LOG_LEVEL_ERROR, id, fmt, ##__VA_ARGS__) #define scanner_err(scanner, fmt, ...) \ scanner_log(scanner, XKB_LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__) +#define scanner_warn_with_code(scanner, id, fmt, ...) \ + scanner_log_with_code(scanner, XKB_LOG_LEVEL_WARNING, id, fmt, ##__VA_ARGS__) + #define scanner_warn(scanner, fmt, ...) \ scanner_log(scanner, XKB_LOG_LEVEL_WARNING, fmt, ##__VA_ARGS__) diff --git a/src/xkbcomp/action.c b/src/xkbcomp/action.c index e2d4c40..1410aab 100644 --- a/src/xkbcomp/action.c +++ b/src/xkbcomp/action.c @@ -190,10 +190,11 @@ fieldText(enum action_field field) /***====================================================================***/ static inline bool -ReportMismatch(struct xkb_context *ctx, enum xkb_action_type action, - enum action_field field, const char *type) +ReportMismatch(struct xkb_context *ctx, xkb_message_code_t code, + enum xkb_action_type action, enum action_field field, + const char *type) { - log_err(ctx, + log_err_with_code(ctx, code, "Value of %s field must be of type %s; " "Action %s definition ignored\n", fieldText(field), type, ActionTypeText(action)); @@ -243,7 +244,8 @@ CheckBooleanFlag(struct xkb_context *ctx, enum xkb_action_type action, return ReportActionNotArray(ctx, action, field); if (!ExprResolveBoolean(ctx, value, &set)) - return ReportMismatch(ctx, action, field, "boolean"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, + action, field, "boolean"); if (set) *flags_inout |= flag; @@ -274,7 +276,7 @@ CheckModifierField(struct xkb_context *ctx, const struct xkb_mod_set *mods, } if (!ExprResolveModMask(ctx, value, MOD_BOTH, mods, mods_rtrn)) - return ReportMismatch(ctx, action, + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, action, ACTION_FIELD_MODIFIERS, "modifier mask"); *flags_inout &= ~ACTION_MODS_LOOKUP_MODMAP; @@ -300,7 +302,8 @@ CheckAffectField(struct xkb_context *ctx, enum xkb_action_type action, return ReportActionNotArray(ctx, action, ACTION_FIELD_AFFECT); if (!ExprResolveEnum(ctx, value, &flags, lockWhich)) - return ReportMismatch(ctx, action, ACTION_FIELD_AFFECT, + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, + action, ACTION_FIELD_AFFECT, "lock, unlock, both, neither"); *flags_inout &= ~(ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK); @@ -359,8 +362,8 @@ CheckGroupField(struct xkb_context *ctx, enum xkb_action_type action, } if (!ExprResolveGroup(ctx, spec, &idx)) - return ReportMismatch(ctx, action, ACTION_FIELD_GROUP, - "integer (range 1..8)"); + return ReportMismatch(ctx, XKB_ERROR_UNSUPPORTED_GROUP_INDEX, action, + ACTION_FIELD_GROUP, "integer (range 1..8)"); /* +n, -n are relative, n is absolute. */ if (value->expr.op == EXPR_NEGATE || value->expr.op == EXPR_UNARY_PLUS) { @@ -416,7 +419,8 @@ HandleMovePtr(struct xkb_context *ctx, const struct xkb_mod_set *mods, return ReportActionNotArray(ctx, action->type, field); if (!ExprResolveInteger(ctx, value, &val)) - return ReportMismatch(ctx, action->type, field, "integer"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, action->type, + field, "integer"); if (val < INT16_MIN || val > INT16_MAX) { log_err(ctx, @@ -462,8 +466,8 @@ HandlePtrBtn(struct xkb_context *ctx, const struct xkb_mod_set *mods, return ReportActionNotArray(ctx, action->type, field); if (!ExprResolveButton(ctx, value, &btn)) - return ReportMismatch(ctx, action->type, field, - "integer (range 1..5)"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, action->type, + field, "integer (range 1..5)"); if (btn < 0 || btn > 5) { log_err(ctx, @@ -487,7 +491,8 @@ HandlePtrBtn(struct xkb_context *ctx, const struct xkb_mod_set *mods, return ReportActionNotArray(ctx, action->type, field); if (!ExprResolveInteger(ctx, value, &val)) - return ReportMismatch(ctx, action->type, field, "integer"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, action->type, + field, "integer"); if (val < 0 || val > 255) { log_err(ctx, @@ -524,8 +529,8 @@ HandleSetPtrDflt(struct xkb_context *ctx, const struct xkb_mod_set *mods, return ReportActionNotArray(ctx, action->type, field); if (!ExprResolveEnum(ctx, value, &val, ptrDflts)) - return ReportMismatch(ctx, action->type, field, - "pointer component"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, action->type, + field, "pointer component"); return true; } else if (field == ACTION_FIELD_BUTTON || field == ACTION_FIELD_VALUE) { @@ -546,8 +551,8 @@ HandleSetPtrDflt(struct xkb_context *ctx, const struct xkb_mod_set *mods, } if (!ExprResolveButton(ctx, button, &btn)) - return ReportMismatch(ctx, action->type, field, - "integer (range 1..5)"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, action->type, + field, "integer (range 1..5)"); if (btn < 0 || btn > 5) { log_err(ctx, @@ -594,8 +599,8 @@ HandleSwitchScreen(struct xkb_context *ctx, const struct xkb_mod_set *mods, } if (!ExprResolveInteger(ctx, scrn, &val)) - return ReportMismatch(ctx, action->type, field, - "integer (0..255)"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, action->type, + field, "integer (0..255)"); if (val < 0 || val > 255) { log_err(ctx, @@ -630,8 +635,8 @@ HandleSetLockControls(struct xkb_context *ctx, const struct xkb_mod_set *mods, return ReportActionNotArray(ctx, action->type, field); if (!ExprResolveMask(ctx, value, &mask, ctrlMaskNames)) - return ReportMismatch(ctx, action->type, field, - "controls mask"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, action->type, + field, "controls mask"); act->ctrls = mask; return true; @@ -658,7 +663,8 @@ HandlePrivate(struct xkb_context *ctx, const struct xkb_mod_set *mods, return ReportActionNotArray(ctx, action->type, field); if (!ExprResolveInteger(ctx, value, &type)) - return ReportMismatch(ctx, ACTION_TYPE_PRIVATE, field, "integer"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, + ACTION_TYPE_PRIVATE, field, "integer"); if (type < 0 || type > 255) { log_err(ctx, @@ -696,7 +702,8 @@ HandlePrivate(struct xkb_context *ctx, const struct xkb_mod_set *mods, size_t len; if (!ExprResolveString(ctx, value, &val)) - return ReportMismatch(ctx, action->type, field, "string"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, + action->type, field, "string"); str = xkb_atom_text(ctx, val); len = strlen(str); @@ -731,7 +738,8 @@ HandlePrivate(struct xkb_context *ctx, const struct xkb_mod_set *mods, } if (!ExprResolveInteger(ctx, value, &datum)) - return ReportMismatch(ctx, act->type, field, "integer"); + return ReportMismatch(ctx, XKB_ERROR_WRONG_FIELD_TYPE, act->type, + field, "integer"); if (datum < 0 || datum > 255) { log_err(ctx, diff --git a/src/xkbcomp/compat.c b/src/xkbcomp/compat.c index b8922c9..121f5f2 100644 --- a/src/xkbcomp/compat.c +++ b/src/xkbcomp/compat.c @@ -124,7 +124,8 @@ static inline bool ReportSIBadType(CompatInfo *info, SymInterpInfo *si, const char *field, const char *wanted) { - return ReportBadType(info->ctx, "symbol interpretation", field, + return ReportBadType(info->ctx, XKB_ERROR_WRONG_FIELD_TYPE, + "symbol interpretation", field, siText(si, info), wanted); } @@ -132,7 +133,8 @@ static inline bool ReportLedBadType(CompatInfo *info, LedInfo *ledi, const char *field, const char *wanted) { - return ReportBadType(info->ctx, "indicator map", field, + return ReportBadType(info->ctx, XKB_ERROR_WRONG_FIELD_TYPE, + "indicator map", field, xkb_atom_text(info->ctx, ledi->led.name), wanted); } diff --git a/src/xkbcomp/expr.c b/src/xkbcomp/expr.c index bbdf038..f935ce6 100644 --- a/src/xkbcomp/expr.c +++ b/src/xkbcomp/expr.c @@ -407,8 +407,9 @@ ExprResolveGroup(struct xkb_context *ctx, const ExprDef *expr, return false; if (result <= 0 || result > XKB_MAX_GROUPS) { - log_err(ctx, "Group index %u is out of range (1..%d)\n", - result, XKB_MAX_GROUPS); + log_err_with_code(ctx, XKB_ERROR_UNSUPPORTED_GROUP_INDEX, + "Group index %u is out of range (1..%d)\n", + result, XKB_MAX_GROUPS); return false; } @@ -429,7 +430,8 @@ ExprResolveLevel(struct xkb_context *ctx, const ExprDef *expr, return false; if (result < 1) { - log_err(ctx, "Shift level %d is out of range\n", result); + log_err_with_code(ctx, XKB_ERROR_UNSUPPORTED_SHIFT_LEVEL, + "Shift level %d is out of range\n", result); return false; } @@ -658,8 +660,9 @@ ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr, return false; if (val < XKB_KEYSYM_MIN) { - log_warn(ctx, "unrecognized keysym \"-0x%x\" (%d)\n", - (unsigned int) -val, val); + log_warn_with_code(ctx, XKB_WARNING_UNRECOGNIZED_KEYSYM, + "unrecognized keysym \"-0x%x\" (%d)\n", + (unsigned int) -val, val); return false; } @@ -674,7 +677,9 @@ ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr, return true; } - log_warn(ctx, "unrecognized keysym \"0x%x\" (%d)\n", val, val); + log_warn_with_code(ctx, XKB_WARNING_UNRECOGNIZED_KEYSYM, + "unrecognized keysym \"0x%x\" (%d)\n", + (unsigned int) val, val); return false; } diff --git a/src/xkbcomp/keycodes.c b/src/xkbcomp/keycodes.c index b8abf36..35c84b7 100644 --- a/src/xkbcomp/keycodes.c +++ b/src/xkbcomp/keycodes.c @@ -472,7 +472,8 @@ HandleLedNameDef(KeyNamesInfo *info, LedNameDef *def, char buf[20]; snprintf(buf, sizeof(buf), "%u", def->ndx); info->errorCount++; - return ReportBadType(info->ctx, "indicator", "name", buf, "string"); + return ReportBadType(info->ctx, XKB_ERROR_WRONG_FIELD_TYPE, + "indicator", "name", buf, "string"); } ledi.merge = merge; diff --git a/src/xkbcomp/parser.y b/src/xkbcomp/parser.y index 7cf2039..1beb30b 100644 --- a/src/xkbcomp/parser.y +++ b/src/xkbcomp/parser.y @@ -46,16 +46,16 @@ struct parser_param { bool more_maps; }; -#define parser_err(param, fmt, ...) \ - scanner_err((param)->scanner, fmt, ##__VA_ARGS__) +#define parser_err(param, error_id, fmt, ...) \ + scanner_err_with_code((param)->scanner, error_id, fmt, ##__VA_ARGS__) -#define parser_warn(param, fmt, ...) \ - scanner_warn((param)->scanner, fmt, ##__VA_ARGS__) +#define parser_warn(param, warning_id, fmt, ...) \ + scanner_warn_with_code((param)->scanner, warning_id, fmt, ##__VA_ARGS__) static void _xkbcommon_error(struct parser_param *param, const char *msg) { - parser_err(param, "%s", msg); + parser_err(param, XKB_ERROR_INVALID_SYNTAX, "%s", msg); } static bool @@ -728,7 +728,12 @@ KeySyms : OBRACE KeySymList CBRACE KeySym : IDENT { if (!resolve_keysym($1, &$$)) { - parser_warn(param, "unrecognized keysym \"%s\"", $1); + parser_warn( + param, + XKB_WARNING_UNRECOGNIZED_KEYSYM, + "unrecognized keysym \"%s\"", + $1 + ); $$ = XKB_KEY_NoSymbol; } free($1); @@ -737,7 +742,12 @@ KeySym : IDENT | Integer { if ($1 < XKB_KEYSYM_MIN) { - parser_warn(param, "unrecognized keysym \"%"PRId64"\"", $1); + parser_warn( + param, + XKB_WARNING_UNRECOGNIZED_KEYSYM, + "unrecognized keysym \"%"PRId64"\"", + $1 + ); $$ = XKB_KEY_NoSymbol; } /* Special case for digits 0..9 */ @@ -748,7 +758,11 @@ KeySym : IDENT if ($1 <= XKB_KEYSYM_MAX) { $$ = (xkb_keysym_t) $1; } else { - parser_warn(param, "unrecognized keysym \"0x%"PRIx64"\"", $1); + parser_warn( + param, XKB_WARNING_UNRECOGNIZED_KEYSYM, + "unrecognized keysym \"0x%"PRIx64"\" " + "(%"PRId64")", $1, $1 + ); $$ = XKB_KEY_NoSymbol; } } diff --git a/src/xkbcomp/scanner.c b/src/xkbcomp/scanner.c index e502216..e78f102 100644 --- a/src/xkbcomp/scanner.c +++ b/src/xkbcomp/scanner.c @@ -100,7 +100,10 @@ skip_more_whitespace_and_comments: else if (scanner_chr(s, 'e')) scanner_buf_append(s, '\033'); else if (scanner_oct(s, &o)) scanner_buf_append(s, (char) o); else { - scanner_warn(s, "unknown escape sequence in string literal"); + // TODO: display actual sequence! See: scanner_peek(s). + // require escaping any potential control character + scanner_warn_with_code(s, XKB_WARNING_UNKNOWN_CHAR_ESCAPE_SEQUENCE, + "unknown escape sequence in string literal"); /* Ignore. */ } } else { @@ -171,7 +174,8 @@ skip_more_whitespace_and_comments: /* Number literal (hexadecimal / decimal / float). */ if (number(s, &yylval->num, &tok)) { if (tok == ERROR_TOK) { - scanner_err(s, "malformed number literal"); + scanner_err_with_code(s, XKB_ERROR_MALFORMED_NUMBER_LITERAL, + "malformed number literal"); return ERROR_TOK; } return tok; diff --git a/src/xkbcomp/symbols.c b/src/xkbcomp/symbols.c index f990529..e438139 100644 --- a/src/xkbcomp/symbols.c +++ b/src/xkbcomp/symbols.c @@ -61,6 +61,10 @@ #include "include.h" #include "keysym.h" + +// TODO: convert log_err to log_err_with_code +// TODO: convert log_vrb to log_vrb_with_code + enum key_repeat { KEY_REPEAT_UNDEFINED = 0, KEY_REPEAT_YES = 1, @@ -240,13 +244,15 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber, xkb_atom_t use = (clobber ? from->type : into->type); xkb_atom_t ignore = (clobber ? into->type : from->type); - if (report) - log_warn(info->ctx, + if (report) { + log_warn_with_code(info->ctx, + XKB_WARNING_CONFLICTING_KEY_TYPE, "Multiple definitions for group %d type of key %s; " "Using %s, ignoring %s\n", group + 1, KeyNameText(info->ctx, key_name), xkb_atom_text(info->ctx, use), xkb_atom_text(info->ctx, ignore)); + } into->type = use; } @@ -284,13 +290,15 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber, use = (clobber ? &fromLevel->action : &intoLevel->action); ignore = (clobber ? &intoLevel->action : &fromLevel->action); - if (report) - log_warn(info->ctx, + if (report) { + log_warn_with_code(info->ctx, + XKB_WARNING_CONFLICTING_KEY_ACTION, "Multiple actions for level %d/group %u on key %s; " "Using %s, ignoring %s\n", i + 1, group + 1, KeyNameText(info->ctx, key_name), ActionTypeText(use->type), ActionTypeText(ignore->type)); + } intoLevel->action = *use; } @@ -307,13 +315,15 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber, fromLevel->num_syms = 0; } else if (!XkbLevelsSameSyms(fromLevel, intoLevel)) { - if (report) - log_warn(info->ctx, + if (report) { + log_warn_with_code(info->ctx, + XKB_WARNING_CONFLICTING_KEY_SYMBOL, "Multiple symbols for level %d/group %u on key %s; " "Using %s, ignoring %s\n", i + 1, group + 1, KeyNameText(info->ctx, key_name), (clobber ? "from" : "to"), (clobber ? "to" : "from")); + } if (clobber) { ClearLevelInfo(intoLevel); @@ -406,12 +416,14 @@ MergeKeys(SymbolsInfo *info, KeyInfo *into, KeyInfo *from, bool same_file) into->defined |= KEY_FIELD_GROUPINFO; } - if (collide) - log_warn(info->ctx, + if (collide) { + log_warn_with_code(info->ctx, + XKB_WARNING_CONFLICTING_KEY_FIELDS, "Symbol map for key %s redefined; " "Using %s definition for conflicting fields\n", KeyNameText(info->ctx, into->name), (clobber ? "first" : "last")); + } ClearKeyInfo(from); InitKeyInfo(info->ctx, from); @@ -464,21 +476,23 @@ AddModMapEntry(SymbolsInfo *info, ModMapEntry *new) use = (clobber ? new->modifier : old->modifier); ignore = (clobber ? old->modifier : new->modifier); - if (new->haveSymbol) - log_warn(info->ctx, + if (new->haveSymbol) { + log_warn_with_code(info->ctx, + XKB_WARNING_CONFLICTING_MODMAP, "Symbol \"%s\" added to modifier map for multiple modifiers; " "Using %s, ignoring %s\n", KeysymText(info->ctx, new->u.keySym), ModIndexText(info->ctx, &info->mods, use), ModIndexText(info->ctx, &info->mods, ignore)); - else - log_warn(info->ctx, + } else { + log_warn_with_code(info->ctx, + XKB_WARNING_CONFLICTING_MODMAP, "Key \"%s\" added to modifier map for multiple modifiers; " "Using %s, ignoring %s\n", KeyNameText(info->ctx, new->u.keyName), ModIndexText(info->ctx, &info->mods, use), ModIndexText(info->ctx, &info->mods, ignore)); - + } old->modifier = use; return true; } @@ -639,7 +653,7 @@ GetGroupIndex(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx, } if (!ExprResolveGroup(info->ctx, arrayNdx, ndx_rtrn)) { - log_err(info->ctx, + log_err_with_code(info->ctx, XKB_ERROR_UNSUPPORTED_GROUP_INDEX, "Illegal group index for %s of key %s\n" "Definition with non-integer array index ignored\n", name, KeyInfoText(info, keyi)); @@ -812,7 +826,7 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field, keyi->defined |= KEY_FIELD_DEFAULT_TYPE; } else if (!ExprResolveGroup(info->ctx, arrayNdx, &ndx)) { - log_err(info->ctx, + log_err_with_code(info->ctx, XKB_ERROR_UNSUPPORTED_GROUP_INDEX, "Illegal group index for type of key %s; " "Definition with non-integer array index ignored\n", KeyInfoText(info, keyi)); @@ -924,7 +938,7 @@ SetSymbolsField(SymbolsInfo *info, KeyInfo *keyi, const char *field, xkb_layout_index_t grp; if (!ExprResolveGroup(info->ctx, value, &grp)) { - log_err(info->ctx, + log_err_with_code(info->ctx, XKB_ERROR_UNSUPPORTED_GROUP_INDEX, "Illegal group index for redirect of key %s; " "Definition with non-integer group ignored\n", KeyInfoText(info, keyi)); @@ -960,7 +974,7 @@ SetGroupName(SymbolsInfo *info, ExprDef *arrayNdx, ExprDef *value) } if (!ExprResolveGroup(info->ctx, arrayNdx, &group)) { - log_err(info->ctx, + log_err_with_code(info->ctx, XKB_ERROR_UNSUPPORTED_GROUP_INDEX, "Illegal index in group name definition; " "Definition with non-integer array index ignored\n"); return false; @@ -980,7 +994,8 @@ SetGroupName(SymbolsInfo *info, ExprDef *arrayNdx, ExprDef *value) group_to_use = info->explicit_group; } else { - log_warn(info->ctx, + log_warn_with_code(info->ctx, + XKB_WARNING_NON_BASE_GROUP_NAME, "An explicit group was specified for the '%s' map, " "but it provides a name for a group other than Group1 (%d); " "Ignoring group name '%s'\n", @@ -1098,12 +1113,14 @@ SetExplicitGroup(SymbolsInfo *info, KeyInfo *keyi) } } - if (warn) - log_warn(info->ctx, + if (warn) { + log_warn_with_code(info->ctx, + XKB_WARNING_MULTIPLE_GROUPS_AT_ONCE, "For the map %s an explicit group specified, " "but key %s has more than one group defined; " "All groups except first one will be ignored\n", info->name, KeyInfoText(info, keyi)); + } darray_resize0(keyi->groups, info->explicit_group + 1); if (info->explicit_group > 0) { @@ -1371,7 +1388,8 @@ FindTypeForGroup(struct xkb_keymap *keymap, KeyInfo *keyi, } if (type_name == XKB_ATOM_NONE) { - log_warn(keymap->ctx, + log_warn_with_code(keymap->ctx, + XKB_WARNING_CANNOT_INFER_KEY_TYPE, "Couldn't find an automatic type for key '%s' group %d with %lu levels; " "Using the default type\n", KeyNameText(keymap->ctx, keyi->name), group + 1, @@ -1384,7 +1402,8 @@ FindTypeForGroup(struct xkb_keymap *keymap, KeyInfo *keyi, break; if (i >= keymap->num_types) { - log_warn(keymap->ctx, + log_warn_with_code(keymap->ctx, + XKB_WARNING_UNDEFINED_KEY_TYPE, "The type \"%s\" for key '%s' group %d was not previously defined; " "Using the default type\n", xkb_atom_text(keymap->ctx, type_name), @@ -1417,7 +1436,8 @@ CopySymbolsDefToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info, */ key = XkbKeyByName(keymap, keyi->name, false); if (!key) { - log_vrb(info->ctx, 5, + log_vrb_with_code(info->ctx, 5, + XKB_WARNING_UNDEFINED_KEYCODE, "Key %s not found in keycodes; Symbols ignored\n", KeyInfoText(info, keyi)); return false; @@ -1460,7 +1480,8 @@ CopySymbolsDefToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info, if (type->num_levels < darray_size(groupi->levels)) { struct xkb_level *leveli; - log_vrb(info->ctx, 1, + log_vrb_with_code(info->ctx, 1, + XKB_WARNING_EXTRA_SYMBOLS_IGNORED, "Type \"%s\" has %d levels, but %s has %d levels; " "Ignoring extra symbols\n", xkb_atom_text(keymap->ctx, type->name), type->num_levels, @@ -1512,7 +1533,8 @@ CopyModMapDefToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info, if (!entry->haveSymbol) { key = XkbKeyByName(keymap, entry->u.keyName, true); if (!key) { - log_vrb(info->ctx, 5, + log_vrb_with_code(info->ctx, 5, + XKB_WARNING_UNDEFINED_KEYCODE, "Key %s not found in keycodes; " "Modifier map entry for %s not updated\n", KeyNameText(info->ctx, entry->u.keyName), @@ -1523,7 +1545,8 @@ CopyModMapDefToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info, else { key = FindKeyForSymbol(keymap, entry->u.keySym); if (!key) { - log_vrb(info->ctx, 5, + log_vrb_with_code(info->ctx, 5, + XKB_WARNING_UNRESOLVED_KEYMAP_SYMBOL, "Key \"%s\" not found in symbol map; " "Modifier map entry for %s not updated\n", KeysymText(info->ctx, entry->u.keySym), diff --git a/src/xkbcomp/types.c b/src/xkbcomp/types.c index 3feaf41..e8e82df 100644 --- a/src/xkbcomp/types.c +++ b/src/xkbcomp/types.c @@ -89,10 +89,10 @@ ReportTypeShouldBeArray(KeyTypesInfo *info, KeyTypeInfo *type, } static inline bool -ReportTypeBadType(KeyTypesInfo *info, KeyTypeInfo *type, - const char *field, const char *wanted) +ReportTypeBadType(KeyTypesInfo *info, xkb_message_code_t code, + KeyTypeInfo *type, const char *field, const char *wanted) { - return ReportBadType(info->ctx, "key type", field, + return ReportBadType(info->ctx, code, "key type", field, TypeTxt(info, type), wanted); } @@ -340,7 +340,8 @@ SetMapEntry(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx, if (!ExprResolveModMask(info->ctx, arrayNdx, MOD_BOTH, &info->mods, &entry.mods.mods)) - return ReportTypeBadType(info, type, "map entry", "modifier mask"); + return ReportTypeBadType(info, XKB_ERROR_UNSUPPORTED_MODIFIER_MASK, + type, "map entry", "modifier mask"); if (entry.mods.mods & (~type->mods)) { log_vrb(info->ctx, 1, @@ -354,9 +355,9 @@ SetMapEntry(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx, } if (!ExprResolveLevel(info->ctx, value, &entry.level)) { - log_err(info->ctx, - "Level specifications in a key type must be integer; " - "Ignoring malformed level specification\n"); + log_err_with_code(info->ctx, XKB_ERROR_UNSUPPORTED_SHIFT_LEVEL, + "Level specifications in a key type must be integer; " + "Ignoring malformed level specification\n"); return false; } @@ -429,8 +430,8 @@ SetPreserve(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx, return ReportTypeShouldBeArray(info, type, "preserve entry"); if (!ExprResolveModMask(info->ctx, arrayNdx, MOD_BOTH, &info->mods, &mods)) - return ReportTypeBadType(info, type, "preserve entry", - "modifier mask"); + return ReportTypeBadType(info, XKB_ERROR_UNSUPPORTED_MODIFIER_MASK, + type, "preserve entry", "modifier mask"); if (mods & ~type->mods) { const char *before, *after; @@ -526,7 +527,8 @@ SetLevelName(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx, return ReportTypeShouldBeArray(info, type, "level name"); if (!ExprResolveLevel(info->ctx, arrayNdx, &level)) - return ReportTypeBadType(info, type, "level name", "integer"); + return ReportTypeBadType(info, XKB_ERROR_UNSUPPORTED_SHIFT_LEVEL, + type, "level name", "integer"); if (!ExprResolveString(info->ctx, value, &level_name)) { log_err(info->ctx, diff --git a/src/xkbcomp/xkbcomp-priv.h b/src/xkbcomp/xkbcomp-priv.h index 6cb774d..5a7765f 100644 --- a/src/xkbcomp/xkbcomp-priv.h +++ b/src/xkbcomp/xkbcomp-priv.h @@ -101,10 +101,10 @@ ReportShouldBeArray(struct xkb_context *ctx, const char *type, } static inline bool -ReportBadType(struct xkb_context *ctx, const char *type, const char *field, - const char *name, const char *wanted) +ReportBadType(struct xkb_context *ctx, xkb_message_code_t code, const char *type, + const char *field, const char *name, const char *wanted) { - log_err(ctx, "The %s %s field must be a %s; " + log_err_with_code(ctx, code, "The %s %s field must be a %s; " "Ignoring illegal assignment in %s\n", type, field, wanted, name); return false;