X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fxkbcomp%2Fkeycodes.c;h=91471ea7fbc75874588f7b5773ffc8fdbd20f120;hb=c0065c95a479c7111417a6547d26594a5e31378b;hp=3fba2a51996a86a997ffe2fc8610b07686f402f0;hpb=81d029f5632d0a2b510d0a29bbda5e91d7958c5d;p=platform%2Fupstream%2Flibxkbcommon.git diff --git a/src/xkbcomp/keycodes.c b/src/xkbcomp/keycodes.c index 3fba2a5..91471ea 100644 --- a/src/xkbcomp/keycodes.c +++ b/src/xkbcomp/keycodes.c @@ -24,755 +24,652 @@ * ********************************************************/ -#include "keycodes.h" -#include "expr.h" -#include "parseutils.h" -#include "alias.h" - -const char * -longText(unsigned long val) -{ - char buf[4]; +#include "config.h" - LongToKeyName(val, buf); - return XkbcKeyNameText(buf); -} +#include "xkbcomp-priv.h" +#include "text.h" +#include "expr.h" +#include "include.h" -/***====================================================================***/ +typedef struct { + enum merge_mode merge; -void -LongToKeyName(unsigned long val, char *name) -{ - name[0] = ((val >> 24) & 0xff); - name[1] = ((val >> 16) & 0xff); - name[2] = ((val >> 8) & 0xff); - name[3] = (val & 0xff); -} + xkb_atom_t alias; + xkb_atom_t real; +} AliasInfo; -/***====================================================================***/ +typedef struct { + enum merge_mode merge; -typedef struct _IndicatorNameInfo { - CommonInfo defs; - int ndx; xkb_atom_t name; - bool virtual; -} IndicatorNameInfo; +} LedNameInfo; -typedef struct _KeyNamesInfo { - char *name; /* e.g. evdev+aliases(qwerty) */ +typedef struct { + char *name; int errorCount; - unsigned file_id; - enum merge_mode merge; - xkb_keycode_t computedMin; /* lowest keycode stored */ - xkb_keycode_t computedMax; /* highest keycode stored */ - xkb_keycode_t explicitMin; - xkb_keycode_t explicitMax; - darray(unsigned long) names; - darray(unsigned int) files; - IndicatorNameInfo *leds; - AliasInfo *aliases; -} KeyNamesInfo; - -static void -HandleKeycodesFile(XkbFile *file, struct xkb_keymap *keymap, - enum merge_mode merge, - KeyNamesInfo *info); -static void -ResizeKeyNameArrays(KeyNamesInfo *info, int newMax) -{ - if (newMax < darray_size(info->names)) - return; + xkb_keycode_t min_key_code; + xkb_keycode_t max_key_code; + darray(xkb_atom_t) key_names; + LedNameInfo led_names[XKB_MAX_LEDS]; + unsigned int num_led_names; + darray(AliasInfo) aliases; - darray_resize0(info->names, newMax + 1); - darray_resize0(info->files, newMax + 1); -} + struct xkb_context *ctx; +} KeyNamesInfo; -static void -InitIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info) -{ - ii->defs.defined = 0; - ii->defs.merge = info->merge; - ii->defs.file_id = info->file_id; - ii->defs.next = NULL; - ii->ndx = 0; - ii->name = XKB_ATOM_NONE; - ii->virtual = false; -} +/***====================================================================***/ static void -ClearIndicatorNameInfo(IndicatorNameInfo * ii, KeyNamesInfo * info) -{ - if (ii == info->leds) { - ClearCommonInfo(&ii->defs); - info->leds = NULL; - } -} - -static IndicatorNameInfo * -NextIndicatorName(KeyNamesInfo * info) +InitAliasInfo(AliasInfo *info, enum merge_mode merge, + xkb_atom_t alias, xkb_atom_t real) { - IndicatorNameInfo *ii; - - ii = uTypedAlloc(IndicatorNameInfo); - if (ii) { - InitIndicatorNameInfo(ii, info); - info->leds = AddCommonInfo(&info->leds->defs, &ii->defs); - } - return ii; + memset(info, 0, sizeof(*info)); + info->merge = merge; + info->alias = alias; + info->real = real; } -static IndicatorNameInfo * -FindIndicatorByIndex(KeyNamesInfo * info, int ndx) +static LedNameInfo * +FindLedByName(KeyNamesInfo *info, xkb_atom_t name, + xkb_led_index_t *idx_out) { - IndicatorNameInfo *old; - - for (old = info->leds; old != NULL; - old = (IndicatorNameInfo *) old->defs.next) { - if (old->ndx == ndx) - return old; + for (xkb_led_index_t idx = 0; idx < info->num_led_names; idx++) { + LedNameInfo *ledi = &info->led_names[idx]; + if (ledi->name == name) { + *idx_out = idx; + return ledi; + } } - return NULL; -} - -static IndicatorNameInfo * -FindIndicatorByName(KeyNamesInfo * info, xkb_atom_t name) -{ - IndicatorNameInfo *old; - for (old = info->leds; old != NULL; - old = (IndicatorNameInfo *) old->defs.next) { - if (old->name == name) - return old; - } return NULL; } static bool -AddIndicatorName(KeyNamesInfo *info, struct xkb_keymap *keymap, - enum merge_mode merge, - IndicatorNameInfo *new) +AddLedName(KeyNamesInfo *info, enum merge_mode merge, bool same_file, + LedNameInfo *new, xkb_led_index_t new_idx) { - IndicatorNameInfo *old; - bool replace; - - replace = (merge == MERGE_REPLACE) || (merge == MERGE_OVERRIDE); - old = FindIndicatorByName(info, new->name); - if (old) { - if (((old->defs.file_id == new->defs.file_id) && (warningLevel > 0)) - || (warningLevel > 9)) { - WARN("Multiple indicators named %s\n", - xkb_atom_text(keymap->ctx, new->name)); - if (old->ndx == new->ndx) { - if (old->virtual != new->virtual) { - if (replace) - old->virtual = new->virtual; - ACTION("Using %s instead of %s\n", - (old->virtual ? "virtual" : "real"), - (old->virtual ? "real" : "virtual")); - } - else { - ACTION("Identical definitions ignored\n"); - } - return true; - } - else { - if (replace) - ACTION("Ignoring %d, using %d\n", old->ndx, new->ndx); - else - ACTION("Using %d, ignoring %d\n", old->ndx, new->ndx); - } - if (replace) { - if (info->leds == old) - info->leds = (IndicatorNameInfo *) old->defs.next; - else { - IndicatorNameInfo *tmp; - tmp = info->leds; - for (; tmp != NULL; - tmp = (IndicatorNameInfo *) tmp->defs.next) { - if (tmp->defs.next == (CommonInfo *) old) { - tmp->defs.next = old->defs.next; - break; - } - } - } - free(old); - } - } - } - old = FindIndicatorByIndex(info, new->ndx); + xkb_led_index_t old_idx; + LedNameInfo *old; + const int verbosity = xkb_context_get_log_verbosity(info->ctx); + const bool report = (same_file && verbosity > 0) || verbosity > 9; + const bool replace = (merge == MERGE_REPLACE || merge == MERGE_OVERRIDE); + + /* LED with the same name already exists. */ + old = FindLedByName(info, new->name, &old_idx); if (old) { - if (((old->defs.file_id == new->defs.file_id) && (warningLevel > 0)) - || (warningLevel > 9)) { - WARN("Multiple names for indicator %d\n", new->ndx); - if ((old->name == new->name) && (old->virtual == new->virtual)) - ACTION("Identical definitions ignored\n"); - else { - const char *oldType, *newType; - xkb_atom_t using, ignoring; - if (old->virtual) - oldType = "virtual indicator"; - else - oldType = "real indicator"; - if (new->virtual) - newType = "virtual indicator"; - else - newType = "real indicator"; - if (replace) { - using = new->name; - ignoring = old->name; - } - else { - using = old->name; - ignoring = new->name; - } - ACTION("Using %s %s, ignoring %s %s\n", - oldType, xkb_atom_text(keymap->ctx, using), - newType, xkb_atom_text(keymap->ctx, ignoring)); - } + if (old_idx == new_idx) { + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Multiple indicators named \"%s\"; " + "Identical definitions ignored\n", + xkb_atom_text(info->ctx, new->name)); + return true; } - if (replace) { - old->name = new->name; - old->virtual = new->virtual; + + if (report) { + xkb_led_index_t use = (replace ? new_idx + 1 : old_idx + 1); + xkb_led_index_t ignore = (replace ? old_idx + 1 : new_idx + 1); + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Multiple indicators named %s; Using %d, ignoring %d\n", + xkb_atom_text(info->ctx, new->name), use, ignore); } + + if (replace) + *old = *new; + return true; } - old = new; - new = NextIndicatorName(info); - if (!new) { - WSGO("Couldn't allocate name for indicator %d\n", old->ndx); - ACTION("Ignored\n"); - return false; + + if (new_idx >= info->num_led_names) + info->num_led_names = new_idx + 1; + + /* LED with the same index already exists. */ + old = &info->led_names[new_idx]; + if (old->name != XKB_ATOM_NONE) { + if (report) { + const xkb_atom_t use = (replace ? new->name : old->name); + const xkb_atom_t ignore = (replace ? old->name : new->name); + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Multiple names for indicator %d; " + "Using %s, ignoring %s\n", new_idx + 1, + xkb_atom_text(info->ctx, use), + xkb_atom_text(info->ctx, ignore)); + } + + if (replace) + *old = *new; + + return true; } - new->name = old->name; - new->ndx = old->ndx; - new->virtual = old->virtual; + + *old = *new; return true; } static void -ClearKeyNamesInfo(KeyNamesInfo * info) +ClearKeyNamesInfo(KeyNamesInfo *info) { free(info->name); - info->name = NULL; - info->computedMax = info->explicitMax = info->explicitMin = 0; - info->computedMin = XKB_KEYCODE_MAX; - darray_free(info->names); - darray_free(info->files); - if (info->leds) - ClearIndicatorNameInfo(info->leds, info); - if (info->aliases) - ClearAliases(&info->aliases); + darray_free(info->key_names); + darray_free(info->aliases); } static void -InitKeyNamesInfo(KeyNamesInfo * info, unsigned file_id) +InitKeyNamesInfo(KeyNamesInfo *info, struct xkb_context *ctx) { - info->name = NULL; - info->leds = NULL; - info->aliases = NULL; - info->file_id = file_id; - darray_init(info->names); - darray_init(info->files); - ClearKeyNamesInfo(info); - info->errorCount = 0; + memset(info, 0, sizeof(*info)); + info->ctx = ctx; + info->min_key_code = XKB_KEYCODE_INVALID; +#if XKB_KEYCODE_INVALID < XKB_KEYCODE_MAX +#error "Hey, you can't be changing stuff like that." +#endif } -static int -FindKeyByLong(KeyNamesInfo * info, unsigned long name) +static xkb_keycode_t +FindKeyByName(KeyNamesInfo *info, xkb_atom_t name) { - uint64_t i; + xkb_keycode_t i; - for (i = info->computedMin; i <= info->computedMax; i++) - if (darray_item(info->names, i) == name) + for (i = info->min_key_code; i <= info->max_key_code; i++) + if (darray_item(info->key_names, i) == name) return i; - return 0; + return XKB_KEYCODE_INVALID; } -/** - * Store the name of the key as a long in the info struct under the given - * keycode. If the same keys is referred to twice, print a warning. - * Note that the key's name is stored as a long, the keycode is the index. - */ static bool -AddKeyName(KeyNamesInfo * info, - xkb_keycode_t kc, char *name, enum merge_mode merge, - unsigned file_id, bool reportCollisions) +AddKeyName(KeyNamesInfo *info, xkb_keycode_t kc, xkb_atom_t name, + enum merge_mode merge, bool same_file, bool report) { - xkb_keycode_t old; - unsigned long lval; - - ResizeKeyNameArrays(info, kc); - - if (kc < info->computedMin) - info->computedMin = kc; - if (kc > info->computedMax) - info->computedMax = kc; - lval = KeyNameToLong(name); - - if (reportCollisions) { - reportCollisions = (warningLevel > 7 || - (warningLevel > 0 && - file_id == darray_item(info->files, kc))); - } - - if (darray_item(info->names, kc) != 0) { - char buf[6]; - - LongToKeyName(darray_item(info->names, kc), buf); - buf[4] = '\0'; - if (darray_item(info->names, kc) == lval && reportCollisions) { - WARN("Multiple identical key name definitions\n"); - ACTION("Later occurences of \"<%s> = %d\" ignored\n", - buf, kc); + xkb_atom_t old_name; + xkb_keycode_t old_kc; + const int verbosity = xkb_context_get_log_verbosity(info->ctx); + + report = report && ((same_file && verbosity > 0) || verbosity > 7); + + if (kc >= darray_size(info->key_names)) + darray_resize0(info->key_names, kc + 1); + + info->min_key_code = MIN(info->min_key_code, kc); + info->max_key_code = MAX(info->max_key_code, kc); + + /* There's already a key with this keycode. */ + old_name = darray_item(info->key_names, kc); + if (old_name != XKB_ATOM_NONE) { + const char *lname = KeyNameText(info->ctx, old_name); + const char *kname = KeyNameText(info->ctx, name); + + if (old_name == name) { + if (report) + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Multiple identical key name definitions; " + "Later occurrences of \"%s = %d\" ignored\n", + lname, kc); return true; } - if (merge == MERGE_AUGMENT) { - if (reportCollisions) { - WARN("Multiple names for keycode %d\n", kc); - ACTION("Using <%s>, ignoring <%s>\n", buf, name); - } + else if (merge == MERGE_AUGMENT) { + if (report) + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Multiple names for keycode %d; " + "Using %s, ignoring %s\n", kc, lname, kname); return true; } else { - if (reportCollisions) { - WARN("Multiple names for keycode %d\n", kc); - ACTION("Using <%s>, ignoring <%s>\n", name, buf); - } - darray_item(info->names, kc) = 0; - darray_item(info->files, kc) = 0; + if (report) + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Multiple names for keycode %d; " + "Using %s, ignoring %s\n", kc, kname, lname); + darray_item(info->key_names, kc) = XKB_ATOM_NONE; } } - old = FindKeyByLong(info, lval); - if ((old != 0) && (old != kc)) { + + /* There's already a key with this name. */ + old_kc = FindKeyByName(info, name); + if (old_kc != XKB_KEYCODE_INVALID && old_kc != kc) { + const char *kname = KeyNameText(info->ctx, name); + if (merge == MERGE_OVERRIDE) { - darray_item(info->names, old) = 0; - darray_item(info->files, old) = 0; - if (reportCollisions) { - WARN("Key name <%s> assigned to multiple keys\n", name); - ACTION("Using %d, ignoring %d\n", kc, old); - } + darray_item(info->key_names, old_kc) = XKB_ATOM_NONE; + if (report) + log_warn(info->ctx, + XKB_WARNING_CONFLICTING_KEY_NAME, + "Key name %s assigned to multiple keys; " + "Using %d, ignoring %d\n", kname, kc, old_kc); } else { - if ((reportCollisions) && (warningLevel > 3)) { - WARN("Key name <%s> assigned to multiple keys\n", name); - ACTION("Using %d, ignoring %d\n", old, kc); - } + if (report) + log_vrb(info->ctx, 3, + XKB_WARNING_CONFLICTING_KEY_NAME, + "Key name %s assigned to multiple keys; " + "Using %d, ignoring %d\n", kname, old_kc, kc); return true; } } - darray_item(info->names, kc) = lval; - darray_item(info->files, kc) = file_id; + + darray_item(info->key_names, kc) = name; return true; } /***====================================================================***/ +static bool +HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge); + static void -MergeIncludedKeycodes(KeyNamesInfo *into, struct xkb_keymap *keymap, - KeyNamesInfo *from, enum merge_mode merge) +MergeIncludedKeycodes(KeyNamesInfo *into, KeyNamesInfo *from, + enum merge_mode merge) { - uint64_t i; - char buf[5]; - if (from->errorCount > 0) { into->errorCount += from->errorCount; return; } + if (into->name == NULL) { into->name = from->name; from->name = NULL; } - ResizeKeyNameArrays(into, from->computedMax); + /* Merge key names. */ + if (darray_empty(into->key_names)) { + into->key_names = from->key_names; + darray_init(from->key_names); + into->min_key_code = from->min_key_code; + into->max_key_code = from->max_key_code; + } + else { + if (darray_size(into->key_names) < darray_size(from->key_names)) + darray_resize0(into->key_names, darray_size(from->key_names)); + + for (unsigned i = from->min_key_code; i <= from->max_key_code; i++) { + xkb_atom_t name = darray_item(from->key_names, i); + if (name == XKB_ATOM_NONE) + continue; - for (i = from->computedMin; i <= from->computedMax; i++) { - if (darray_item(from->names, i) == 0) - continue; - LongToKeyName(darray_item(from->names, i), buf); - buf[4] = '\0'; - if (!AddKeyName(into, i, buf, merge, from->file_id, false)) - into->errorCount++; + if (!AddKeyName(into, i, name, merge, true, false)) + into->errorCount++; + } + } + + /* Merge key aliases. */ + if (darray_empty(into->aliases)) { + into->aliases = from->aliases; + darray_init(from->aliases); } - if (from->leds) { - IndicatorNameInfo *led, *next; - for (led = from->leds; led != NULL; led = next) { - if (merge != MERGE_DEFAULT) - led->defs.merge = merge; - if (!AddIndicatorName(into, keymap, led->defs.merge, led)) + else { + AliasInfo *alias; + + darray_foreach(alias, from->aliases) { + KeyAliasDef def; + + def.merge = (merge == MERGE_DEFAULT ? alias->merge : merge); + def.alias = alias->alias; + def.real = alias->real; + + if (!HandleAliasDef(into, &def, def.merge)) into->errorCount++; - next = (IndicatorNameInfo *) led->defs.next; } } - if (!MergeAliases(&into->aliases, &from->aliases, merge)) - into->errorCount++; - if (from->explicitMin != 0) { - if ((into->explicitMin == 0) - || (into->explicitMin > from->explicitMin)) - into->explicitMin = from->explicitMin; + + /* Merge LED names. */ + if (into->num_led_names == 0) { + memcpy(into->led_names, from->led_names, + sizeof(*from->led_names) * from->num_led_names); + into->num_led_names = from->num_led_names; + from->num_led_names = 0; } - if (from->explicitMax > 0) { - if ((into->explicitMax == 0) - || (into->explicitMax < from->explicitMax)) - into->explicitMax = from->explicitMax; + else { + for (xkb_led_index_t idx = 0; idx < from->num_led_names; idx++) { + LedNameInfo *ledi = &from->led_names[idx]; + + if (ledi->name == XKB_ATOM_NONE) + continue; + + ledi->merge = (merge == MERGE_DEFAULT ? ledi->merge : merge); + if (!AddLedName(into, ledi->merge, false, ledi, idx)) + into->errorCount++; + } } } -/** - * Handle the given include statement (e.g. "include "evdev+aliases(qwerty)"). - * - * @param stmt The include statement from the keymap file. - * @param keymap Unused for all but the keymap->flags. - * @param info Struct to store the key info in. - */ +static void +HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge); + static bool -HandleIncludeKeycodes(IncludeStmt *stmt, struct xkb_keymap *keymap, - KeyNamesInfo *info) +HandleIncludeKeycodes(KeyNamesInfo *info, IncludeStmt *include) { - enum merge_mode newMerge; - XkbFile *rtrn; KeyNamesInfo included; - bool haveSelf; - memset(&included, 0, sizeof(included)); + InitKeyNamesInfo(&included, info->ctx); + included.name = include->stmt; + include->stmt = NULL; - haveSelf = false; - if ((stmt->file == NULL) && (stmt->map == NULL)) { - haveSelf = true; - included = *info; - memset(info, 0, sizeof(KeyNamesInfo)); - } - else if (stmt->file && strcmp(stmt->file, "computed") == 0) { - keymap->flags |= AutoKeyNames; - info->explicitMin = 0; - info->explicitMax = XKB_KEYCODE_MAX; - return (info->errorCount == 0); - } /* parse file, store returned info in the xkb struct */ - else if (ProcessIncludeFile(keymap->ctx, stmt, FILE_TYPE_KEYCODES, &rtrn, - &newMerge)) { - InitKeyNamesInfo(&included, rtrn->id); - HandleKeycodesFile(rtrn, keymap, MERGE_OVERRIDE, &included); - if (stmt->stmt != NULL) { - free(included.name); - included.name = stmt->stmt; - stmt->stmt = NULL; - } - FreeXKBFile(rtrn); - } - else { - info->errorCount += 10; /* XXX: why 10?? */ - return false; - } - /* Do we have more than one include statement? */ - if ((stmt->next != NULL) && (included.errorCount < 1)) { - IncludeStmt *next; - unsigned op; + for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) { KeyNamesInfo next_incl; + XkbFile *file; - for (next = stmt->next; next != NULL; next = next->next) { - if ((next->file == NULL) && (next->map == NULL)) { - haveSelf = true; - MergeIncludedKeycodes(&included, keymap, info, next->merge); - ClearKeyNamesInfo(info); - } - else if (ProcessIncludeFile(keymap->ctx, next, FILE_TYPE_KEYCODES, - &rtrn, &op)) { - InitKeyNamesInfo(&next_incl, rtrn->id); - HandleKeycodesFile(rtrn, keymap, MERGE_OVERRIDE, &next_incl); - MergeIncludedKeycodes(&included, keymap, &next_incl, op); - ClearKeyNamesInfo(&next_incl); - FreeXKBFile(rtrn); - } - else { - info->errorCount += 10; /* XXX: Why 10?? */ - ClearKeyNamesInfo(&included); - return false; - } + file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_KEYCODES); + if (!file) { + info->errorCount += 10; + ClearKeyNamesInfo(&included); + return false; } + + InitKeyNamesInfo(&next_incl, info->ctx); + + HandleKeycodesFile(&next_incl, file, MERGE_OVERRIDE); + + MergeIncludedKeycodes(&included, &next_incl, stmt->merge); + + ClearKeyNamesInfo(&next_incl); + FreeXkbFile(file); } - if (haveSelf) - *info = included; - else { - MergeIncludedKeycodes(info, keymap, &included, newMerge); - ClearKeyNamesInfo(&included); - } + + MergeIncludedKeycodes(info, &included, include->merge); + ClearKeyNamesInfo(&included); + return (info->errorCount == 0); } -/** - * Parse the given statement and store the output in the info struct. - * e.g. = 9 - */ -static int -HandleKeycodeDef(KeycodeDef *stmt, enum merge_mode merge, KeyNamesInfo *info) +static bool +HandleKeycodeDef(KeyNamesInfo *info, KeycodeDef *stmt, enum merge_mode merge) { - if ((info->explicitMin != 0 && stmt->value < info->explicitMin) || - (info->explicitMax != 0 && stmt->value > info->explicitMax)) { - ERROR("Illegal keycode %lu for name <%s>\n", stmt->value, stmt->name); - ACTION("Must be in the range %d-%d inclusive\n", - info->explicitMin, - info->explicitMax ? info->explicitMax : XKB_KEYCODE_MAX); - return 0; - } if (stmt->merge != MERGE_DEFAULT) { if (stmt->merge == MERGE_REPLACE) merge = MERGE_OVERRIDE; else merge = stmt->merge; } - return AddKeyName(info, stmt->value, stmt->name, merge, info->file_id, - true); -} -#define MIN_KEYCODE_DEF 0 -#define MAX_KEYCODE_DEF 1 + if (stmt->value < 0 || stmt->value > XKB_KEYCODE_MAX) { + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Illegal keycode %lld: must be between 0..%u; " + "Key ignored\n", (long long) stmt->value, XKB_KEYCODE_MAX); + return false; + } -/** - * Handle the minimum/maximum statement of the xkb file. - * Sets explicitMin/Max of the info struct. - * - * @return 1 on success, 0 otherwise. - */ -static int -HandleKeyNameVar(VarDef *stmt, struct xkb_keymap *keymap, KeyNamesInfo *info) + return AddKeyName(info, (xkb_keycode_t) stmt->value, + stmt->name, merge, false, true); +} + +static bool +HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge) { - ExprResult tmp, field; - ExprDef *arrayNdx; - int which; + AliasInfo *old, new; + + darray_foreach(old, info->aliases) { + if (old->alias == def->alias) { + if (def->real == old->real) { + log_vrb(info->ctx, 1, + XKB_WARNING_CONFLICTING_KEY_NAME, + "Alias of %s for %s declared more than once; " + "First definition ignored\n", + KeyNameText(info->ctx, def->alias), + KeyNameText(info->ctx, def->real)); + } + else { + xkb_atom_t use, ignore; - if (ExprResolveLhs(keymap, stmt->name, &tmp, &field, &arrayNdx) == 0) - return 0; /* internal error, already reported */ + use = (merge == MERGE_AUGMENT ? old->real : def->real); + ignore = (merge == MERGE_AUGMENT ? def->real : old->real); - if (tmp.str != NULL) { - ERROR("Unknown element %s encountered\n", tmp.str); - ACTION("Default for field %s ignored\n", field.str); - goto err_out; - } - if (strcasecmp(field.str, "minimum") == 0) - which = MIN_KEYCODE_DEF; - else if (strcasecmp(field.str, "maximum") == 0) - which = MAX_KEYCODE_DEF; - else { - ERROR("Unknown field encountered\n"); - ACTION("Assigment to field %s ignored\n", field.str); - goto err_out; - } - if (arrayNdx != NULL) { - ERROR("The %s setting is not an array\n", field.str); - ACTION("Illegal array reference ignored\n"); - goto err_out; - } + log_warn(info->ctx, + XKB_WARNING_CONFLICTING_KEY_NAME, + "Multiple definitions for alias %s; " + "Using %s, ignoring %s\n", + KeyNameText(info->ctx, old->alias), + KeyNameText(info->ctx, use), + KeyNameText(info->ctx, ignore)); - if (ExprResolveKeyCode(keymap->ctx, stmt->value, &tmp) == 0) { - ACTION("Assignment to field %s ignored\n", field.str); - goto err_out; - } - if (tmp.uval > XKB_KEYCODE_MAX) { - ERROR - ("Illegal keycode %d (must be in the range %d-%d inclusive)\n", - tmp.uval, 0, XKB_KEYCODE_MAX); - ACTION("Value of \"%s\" not changed\n", field.str); - goto err_out; - } - if (which == MIN_KEYCODE_DEF) { - if ((info->explicitMax > 0) && (info->explicitMax < tmp.uval)) { - ERROR - ("Minimum key code (%d) must be <= maximum key code (%d)\n", - tmp.uval, info->explicitMax); - ACTION("Minimum key code value not changed\n"); - goto err_out; - } - if ((info->computedMax > 0) && (info->computedMin < tmp.uval)) { - ERROR - ("Minimum key code (%d) must be <= lowest defined key (%d)\n", - tmp.uval, info->computedMin); - ACTION("Minimum key code value not changed\n"); - goto err_out; + old->real = use; + } + + old->merge = merge; + return true; } - info->explicitMin = tmp.uval; } - if (which == MAX_KEYCODE_DEF) { - if ((info->explicitMin > 0) && (info->explicitMin > tmp.uval)) { - ERROR("Maximum code (%d) must be >= minimum key code (%d)\n", - tmp.uval, info->explicitMin); - ACTION("Maximum code value not changed\n"); - goto err_out; - } - if ((info->computedMax > 0) && (info->computedMax > tmp.uval)) { - ERROR - ("Maximum code (%d) must be >= highest defined key (%d)\n", - tmp.uval, info->computedMax); - ACTION("Maximum code value not changed\n"); - goto err_out; - } - info->explicitMax = tmp.uval; + + InitAliasInfo(&new, merge, def->alias, def->real); + darray_append(info->aliases, new); + return true; +} + +static bool +HandleKeyNameVar(KeyNamesInfo *info, VarDef *stmt) +{ + const char *elem, *field; + ExprDef *arrayNdx; + + if (!ExprResolveLhs(info->ctx, stmt->name, &elem, &field, &arrayNdx)) + return false; + + if (elem) { + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, "Unknown element %s encountered; " + "Default for field %s ignored\n", elem, field); + return false; } - free(field.str); - return 1; + if (!istreq(field, "minimum") && !istreq(field, "maximum")) { + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, "Unknown field encountered; " + "Assignment to field %s ignored\n", field); + return false; + } -err_out: - free(field.str); - return 0; + /* We ignore explicit min/max statements, we always use computed. */ + return true; } -static int -HandleIndicatorNameDef(IndicatorNameDef *def, struct xkb_keymap *keymap, - enum merge_mode merge, KeyNamesInfo *info) +static bool +HandleLedNameDef(KeyNamesInfo *info, LedNameDef *def, + enum merge_mode merge) { - IndicatorNameInfo ii; - ExprResult tmp; + LedNameInfo ledi; + xkb_atom_t name; - if ((def->ndx < 1) || (def->ndx > XkbNumIndicators)) { + if (def->ndx < 1 || def->ndx > XKB_MAX_LEDS) { info->errorCount++; - ERROR("Name specified for illegal indicator index %d\n", def->ndx); - ACTION("Ignored\n"); + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Illegal indicator index (%d) specified; must be between 1 .. %d; " + "Ignored\n", def->ndx, XKB_MAX_LEDS); return false; } - InitIndicatorNameInfo(&ii, info); - ii.ndx = def->ndx; - if (!ExprResolveString(keymap->ctx, def->name, &tmp)) { + + if (!ExprResolveString(info->ctx, def->name, &name)) { char buf[20]; - snprintf(buf, sizeof(buf), "%d", def->ndx); + snprintf(buf, sizeof(buf), "%u", def->ndx); info->errorCount++; - return ReportBadType("indicator", "name", buf, "string"); + return ReportBadType(info->ctx, XKB_ERROR_WRONG_FIELD_TYPE, + "indicator", "name", buf, "string"); } - ii.name = xkb_atom_intern(keymap->ctx, tmp.str); - free(tmp.str); - ii.virtual = def->virtual; - if (!AddIndicatorName(info, keymap, merge, &ii)) - return false; - return true; + + ledi.merge = merge; + ledi.name = name; + return AddLedName(info, merge, true, &ledi, def->ndx - 1); } -/** - * Handle the xkb_keycodes section of a xkb file. - * All information about parsed keys is stored in the info struct. - * - * Such a section may have include statements, in which case this function is - * semi-recursive (it calls HandleIncludeKeycodes, which may call - * HandleKeycodesFile again). - * - * @param file The input file (parsed xkb_keycodes section) - * @param xkb Necessary to pass down, may have flags changed. - * @param merge Merge strategy (MERGE_OVERRIDE, etc.) - * @param info Struct to contain the fully parsed key information. - */ static void -HandleKeycodesFile(XkbFile *file, struct xkb_keymap *keymap, - enum merge_mode merge, KeyNamesInfo *info) +HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge) { - ParseCommon *stmt; + bool ok; free(info->name); - info->name = uDupString(file->name); - stmt = file->defs; - while (stmt) - { - switch (stmt->stmtType) { - case StmtInclude: /* e.g. include "evdev+aliases(qwerty)" */ - if (!HandleIncludeKeycodes((IncludeStmt *) stmt, keymap, info)) - info->errorCount++; - break; - case StmtKeycodeDef: /* e.g. = 9; */ - if (!HandleKeycodeDef((KeycodeDef *) stmt, merge, info)) - info->errorCount++; + info->name = strdup_safe(file->name); + + for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) { + switch (stmt->type) { + case STMT_INCLUDE: + ok = HandleIncludeKeycodes(info, (IncludeStmt *) stmt); break; - case StmtKeyAliasDef: /* e.g. alias = ; */ - if (!HandleAliasDef((KeyAliasDef *) stmt, merge, info->file_id, - &info->aliases)) - info->errorCount++; + case STMT_KEYCODE: + ok = HandleKeycodeDef(info, (KeycodeDef *) stmt, merge); break; - case StmtVarDef: /* e.g. minimum, maximum */ - if (!HandleKeyNameVar((VarDef *) stmt, keymap, info)) - info->errorCount++; + case STMT_ALIAS: + ok = HandleAliasDef(info, (KeyAliasDef *) stmt, merge); break; - case StmtIndicatorNameDef: /* e.g. indicator 1 = "Caps Lock"; */ - if (!HandleIndicatorNameDef((IndicatorNameDef *) stmt, keymap, - merge, info)) - info->errorCount++; + case STMT_VAR: + ok = HandleKeyNameVar(info, (VarDef *) stmt); break; - case StmtInterpDef: - case StmtVModDef: - ERROR("Keycode files may define key and indicator names only\n"); - ACTION("Ignoring definition of %s\n", - ((stmt->stmtType == - StmtInterpDef) ? "a symbol interpretation" : - "virtual modifiers")); - info->errorCount++; + case STMT_LED_NAME: + ok = HandleLedNameDef(info, (LedNameDef *) stmt, merge); break; default: - WSGO("Unexpected statement type %d in HandleKeycodesFile\n", - stmt->stmtType); + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Keycode files may define key and indicator names only; " + "Ignoring %s\n", stmt_type_to_string(stmt->type)); + ok = false; break; } - stmt = stmt->next; + + if (!ok) + info->errorCount++; + if (info->errorCount > 10) { -#ifdef NOISY - ERROR("Too many errors\n"); -#endif - ACTION("Abandoning keycodes file \"%s\"\n", file->topName); + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Abandoning keycodes file \"%s\"\n", + file->name); break; } } } -/** - * Compile the xkb_keycodes section, parse it's output, return the results. - * - * @param file The parsed XKB file (may have include statements requiring - * further parsing) - * @param result The effective keycodes, as gathered from the file. - * @param merge Merge strategy. - * - * @return true on success, false otherwise. - */ -bool -CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap, - enum merge_mode merge) +/***====================================================================***/ + +static bool +CopyKeyNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info) { - xkb_keycode_t kc; - KeyNamesInfo info; /* contains all the info after parsing */ + struct xkb_key *keys; + xkb_keycode_t min_key_code, max_key_code, kc; - InitKeyNamesInfo(&info, file->id); + min_key_code = info->min_key_code; + max_key_code = info->max_key_code; + /* If the keymap has no keys, let's just use the safest pair we know. */ + if (min_key_code == XKB_KEYCODE_INVALID) { + min_key_code = 8; + max_key_code = 255; + } - HandleKeycodesFile(file, keymap, merge, &info); + keys = calloc(max_key_code + 1, sizeof(*keys)); + if (!keys) + return false; - /* all the keys are now stored in info */ + for (kc = min_key_code; kc <= max_key_code; kc++) + keys[kc].keycode = kc; - if (info.errorCount != 0) - goto err_info; + for (kc = info->min_key_code; kc <= info->max_key_code; kc++) + keys[kc].name = darray_item(info->key_names, kc); - if (info.explicitMin > 0) /* if "minimum" statement was present */ - keymap->min_key_code = info.explicitMin; - else - keymap->min_key_code = info.computedMin; + keymap->min_key_code = min_key_code; + keymap->max_key_code = max_key_code; + keymap->keys = keys; + return true; +} - if (info.explicitMax > 0) /* if "maximum" statement was present */ - keymap->max_key_code = info.explicitMax; - else - keymap->max_key_code = info.computedMax; +static bool +CopyKeyAliasesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info) +{ + AliasInfo *alias; + unsigned i, num_key_aliases; + struct xkb_key_alias *key_aliases; + + /* + * Do some sanity checking on the aliases. We can't do it before + * because keys and their aliases may be added out-of-order. + */ + num_key_aliases = 0; + darray_foreach(alias, info->aliases) { + /* Check that ->real is a key. */ + if (!XkbKeyByName(keymap, alias->real, false)) { + log_vrb(info->ctx, 5, + XKB_WARNING_UNDEFINED_KEYCODE, + "Attempt to alias %s to non-existent key %s; Ignored\n", + KeyNameText(info->ctx, alias->alias), + KeyNameText(info->ctx, alias->real)); + alias->real = XKB_ATOM_NONE; + continue; + } - darray_resize0(keymap->key_names, keymap->max_key_code + 1); - for (kc = info.computedMin; kc <= info.computedMax; kc++) - LongToKeyName(darray_item(info.names, kc), - darray_item(keymap->key_names, kc).name); + /* Check that ->alias is not a key. */ + if (XkbKeyByName(keymap, alias->alias, false)) { + log_vrb(info->ctx, 5, + XKB_WARNING_ILLEGAL_KEYCODE_ALIAS, + "Attempt to create alias with the name of a real key; " + "Alias \"%s = %s\" ignored\n", + KeyNameText(info->ctx, alias->alias), + KeyNameText(info->ctx, alias->real)); + alias->real = XKB_ATOM_NONE; + continue; + } - if (info.name) - keymap->keycodes_section_name = strdup(info.name); + num_key_aliases++; + } - if (info.leds) { - IndicatorNameInfo *ii; + /* Copy key aliases. */ + key_aliases = NULL; + if (num_key_aliases > 0) { + key_aliases = calloc(num_key_aliases, sizeof(*key_aliases)); + if (!key_aliases) + return false; - for (ii = info.leds; ii; ii = (IndicatorNameInfo *) ii->defs.next) { - free(keymap->indicator_names[ii->ndx - 1]); - keymap->indicator_names[ii->ndx - 1] = - xkb_atom_strdup(keymap->ctx, ii->name); + i = 0; + darray_foreach(alias, info->aliases) { + if (alias->real != XKB_ATOM_NONE) { + key_aliases[i].alias = alias->alias; + key_aliases[i].real = alias->real; + i++; + } } } - ApplyAliases(keymap, &info.aliases); + keymap->num_key_aliases = num_key_aliases; + keymap->key_aliases = key_aliases; + return true; +} + +static bool +CopyLedNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info) +{ + keymap->num_leds = info->num_led_names; + for (xkb_led_index_t idx = 0; idx < info->num_led_names; idx++) { + LedNameInfo *ledi = &info->led_names[idx]; + + if (ledi->name == XKB_ATOM_NONE) + continue; + + keymap->leds[idx].name = ledi->name; + } + + return true; +} + +static bool +CopyKeyNamesInfoToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info) +{ + /* This function trashes keymap on error, but that's OK. */ + if (!CopyKeyNamesToKeymap(keymap, info) || + !CopyKeyAliasesToKeymap(keymap, info) || + !CopyLedNamesToKeymap(keymap, info)) + return false; + + keymap->keycodes_section_name = strdup_safe(info->name); + XkbEscapeMapName(keymap->keycodes_section_name); + return true; +} + +/***====================================================================***/ + +bool +CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap, + enum merge_mode merge) +{ + KeyNamesInfo info; + + InitKeyNamesInfo(&info, keymap->ctx); + + HandleKeycodesFile(&info, file, merge); + if (info.errorCount != 0) + goto err_info; + + if (!CopyKeyNamesInfoToKeymap(keymap, &info)) + goto err_info; ClearKeyNamesInfo(&info); return true;