summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUli Schlachter <psychon@znc.in>2015-04-04 10:59:12 +0200
committerUli Schlachter <psychon@znc.in>2015-04-04 10:59:12 +0200
commit4ed12c46dec9a3055e009c5ecd6cba5c258ce642 (patch)
tree5f7bae593670891c0f61b1a7af9d7e6ebd250f2a
parent9f93cefb40104828049e6de82f98c1f110a684a5 (diff)
Don't check codes to be in range, but find "best match"
If some new events are added to an extension, older implementations register a smaller portion of the event number space than this library possible knows. So we cannot just look for some extension that has some code "in range", but we need to find the best one (with the largest base). Signed-off-by: Uli Schlachter <psychon@znc.in>
-rw-r--r--src/xcb_errors.c56
1 files changed, 40 insertions, 16 deletions
diff --git a/src/xcb_errors.c b/src/xcb_errors.c
index 7594c31..25b42d4 100644
--- a/src/xcb_errors.c
+++ b/src/xcb_errors.c
@@ -28,8 +28,6 @@
#include <stdlib.h>
#include <string.h>
-#define IS_IN_RANGE(value, begin, length) ((value) >= (begin) && (value) < (begin) + (length))
-
struct extension_info_t {
struct extension_info_t *next;
struct static_extension_info_t static_info;
@@ -151,29 +149,55 @@ const char *xcb_errors_get_name_for_minor_code(xcb_errors_context_t *ctx,
const char *xcb_errors_get_name_for_event(xcb_errors_context_t *ctx,
uint8_t event_code)
{
- struct extension_info_t *info = ctx->extensions;
-
- while (info && (info->first_event == 0
- || !IS_IN_RANGE(event_code, info->first_event, info->static_info.num_events)))
- info = info->next;
+ struct extension_info_t *best = NULL;
+ struct extension_info_t *next = ctx->extensions;
+
+ /* Find the extension with the largest first_event <= event_code. Thanks
+ * to this we do the right thing if the server only supports an older
+ * version of some extension which had less events.
+ */
+ while (next) {
+ struct extension_info_t *current = next;
+ next = next->next;
+
+ if (current->first_event > event_code)
+ continue;
+ if (best != NULL && best->first_event > current->first_event)
+ continue;
+ best = current;
+ }
- if (info == NULL)
+ if (best == NULL || best->first_event == 0)
+ /* Nothing found */
return get_strings_entry(xproto_info.strings_events, event_code);
- return get_strings_entry(info->static_info.strings_events, event_code - info->first_event);
+ return get_strings_entry(best->static_info.strings_events, event_code - best->first_event);
}
const char *xcb_errors_get_name_for_error(xcb_errors_context_t *ctx,
uint8_t error_code)
{
- struct extension_info_t *info = ctx->extensions;
-
- while (info && (info->first_error == 0
- || !IS_IN_RANGE(error_code, info->first_error, info->static_info.num_errors)))
- info = info->next;
+ struct extension_info_t *best = NULL;
+ struct extension_info_t *next = ctx->extensions;
+
+ /* Find the extension with the largest first_error <= error_code. Thanks
+ * to this we do the right thing if the server only supports an older
+ * version of some extension which had less events.
+ */
+ while (next) {
+ struct extension_info_t *current = next;
+ next = next->next;
+
+ if (current->first_error > error_code)
+ continue;
+ if (best != NULL && best->first_error > current->first_error)
+ continue;
+ best = current;
+ }
- if (info == NULL)
+ if (best == NULL || best->first_error == 0)
+ /* Nothing found */
return get_strings_entry(xproto_info.strings_errors, error_code);
- return get_strings_entry(info->static_info.strings_errors, error_code - info->first_error);
+ return get_strings_entry(best->static_info.strings_errors, error_code - best->first_error);
}