diff --git a/include/xkbcommon/xkbcommon-compose.h b/include/xkbcommon/xkbcommon-compose.h index 8b41b987a..607cae89c 100644 --- a/include/xkbcommon/xkbcommon-compose.h +++ b/include/xkbcommon/xkbcommon-compose.h @@ -299,6 +299,95 @@ xkb_compose_table_ref(struct xkb_compose_table *table); void xkb_compose_table_unref(struct xkb_compose_table *table); +/** + * @struct xkb_compose_table_entry + * Opaque Compose table entry object. + * + * Represents a single entry in a Compose file in the iteration API. + * It is immutable. + * + * @sa xkb_compose_table_for_each + * @since 1.5.0 + */ +struct xkb_compose_table_entry; + +/** + * Get the left-hand side of a Compose table entry. + * + * For example, given the following entry + * \ \ : "~" asciitilde # TILDE + * returns `{XKB_KEY_dead_tilde, XKB_KEY_space}`. + * + * @returns The array of left-hand side keysyms. The number of keysyms + * is returned in the nsyms out-parameter. + * + * @memberof xkb_compose_table_entry + * @since 1.5.0 + */ +const xkb_keysym_t * +xkb_compose_table_entry_lhs(struct xkb_compose_table_entry *entry, + size_t *nsyms); + +/** + * Get the right-hand result keysym of a Compose table entry. + * + * For example, given the following entry + * \ \ : "~" asciitilde # TILDE + * it will return `XKB_KEY_asciitilde`. + * + * The keysym is optional; if the entry does not specify a keysym, + * returns `XKB_KEY_NoSymbol`. + * + * @memberof xkb_compose_table_entry + * @since 1.5.0 + */ +xkb_keysym_t +xkb_compose_table_entry_keysym(struct xkb_compose_table_entry *entry); + +/** + * Get the right-hand result string of a Compose table entry. + * + * The string is UTF-8 encoded and `\0`-terminated. + * + * For example, given the following entry + * \ \ : "~" asciitilde # TILDE + * it will return `"~"`. + * + * The string is optional; if the entry does not specify a string, + * returns the empty string. + * + * @memberof xkb_compose_table_entry + * @since 1.5.0 + */ +const char * +xkb_compose_table_entry_utf8(struct xkb_compose_table_entry *entry); + +/** + * The iterator function type used by xkb_compose_table_for_each(). + * + * @sa xkb_compose_table_for_each + * @memberof xkb_compose + * @since 1.5.0 + */ +typedef void +(*xkb_compose_table_iter_t)(struct xkb_compose_table_entry *entry, + void *data); + +/** + * Run a specified function for every valid entry in the table. + * + * The entries are returned in lexicographic order of the left-hand + * side of entries. This does not correspond to the order in which + * the entries appear in the Compose file. + * + * @memberof xkb_compose_table + * @since 1.5.0 + */ +void +xkb_compose_table_for_each(struct xkb_compose_table *table, + xkb_compose_table_iter_t iter, + void *data); + /** Flags for compose state creation. */ enum xkb_compose_state_flags { /** Do not apply any flags. */ diff --git a/src/compose/parser.c b/src/compose/parser.c index 124456d11..4adbe92d2 100644 --- a/src/compose/parser.c +++ b/src/compose/parser.c @@ -63,9 +63,6 @@ OR PERFORMANCE OF THIS SOFTWARE. #include "utf8.h" #include "parser.h" -#define MAX_LHS_LEN 10 -#define MAX_INCLUDE_DEPTH 5 - /* * Grammar adapted from libX11/modules/im/ximcp/imLcPrs.c. * See also the XCompose(5) manpage. diff --git a/src/compose/parser.h b/src/compose/parser.h index 3f64a0740..487f1a9f8 100644 --- a/src/compose/parser.h +++ b/src/compose/parser.h @@ -24,6 +24,9 @@ #ifndef COMPOSE_PARSER_H #define COMPOSE_PARSER_H +#define MAX_LHS_LEN 10 +#define MAX_INCLUDE_DEPTH 5 + bool parse_string(struct xkb_compose_table *table, const char *string, size_t len, diff --git a/src/compose/table.c b/src/compose/table.c index ea5e45a84..8227a0e2c 100644 --- a/src/compose/table.c +++ b/src/compose/table.c @@ -27,6 +27,7 @@ #include "table.h" #include "parser.h" #include "paths.h" +#include "xkbcommon/xkbcommon.h" static struct xkb_compose_table * xkb_compose_table_new(struct xkb_context *ctx, @@ -226,3 +227,64 @@ xkb_compose_table_new_from_locale(struct xkb_context *ctx, free(path); return table; } + +XKB_EXPORT const xkb_keysym_t * +xkb_compose_table_entry_lhs(struct xkb_compose_table_entry *entry, + size_t *nsyms) +{ + *nsyms = entry->nsyms; + return entry->syms; +} + +XKB_EXPORT xkb_keysym_t +xkb_compose_table_entry_keysym(struct xkb_compose_table_entry *entry) +{ + return entry->keysym; +} + +XKB_EXPORT const char * +xkb_compose_table_entry_utf8(struct xkb_compose_table_entry *entry) +{ + return entry->utf8; +} + +static void +for_each_helper(struct xkb_compose_table *table, + xkb_compose_table_iter_t iter, + void *data, + xkb_keysym_t *syms, + size_t nsyms, + uint16_t p) +{ + if (!p) { + return; + } + const struct compose_node *node = &darray_item(table->nodes, p); + for_each_helper(table, iter, data, syms, nsyms, node->lokid); + syms[nsyms++] = node->keysym; + if (node->is_leaf) { + struct xkb_compose_table_entry entry = { + .syms = syms, + .nsyms = nsyms, + .keysym = node->leaf.keysym, + .utf8 = &darray_item(table->utf8, node->leaf.utf8), + }; + iter(&entry, data); + } else { + for_each_helper(table, iter, data, syms, nsyms, node->internal.eqkid); + } + nsyms--; + for_each_helper(table, iter, data, syms, nsyms, node->hikid); +} + +XKB_EXPORT void +xkb_compose_table_for_each(struct xkb_compose_table *table, + xkb_compose_table_iter_t iter, + void *data) +{ + if (darray_size(table->nodes) <= 1) { + return; + } + xkb_keysym_t syms[MAX_LHS_LEN]; + for_each_helper(table, iter, data, syms, 0, 1); +} diff --git a/src/compose/table.h b/src/compose/table.h index 825a8e2e8..eda042053 100644 --- a/src/compose/table.h +++ b/src/compose/table.h @@ -119,4 +119,11 @@ struct xkb_compose_table { darray(struct compose_node) nodes; }; +struct xkb_compose_table_entry { + xkb_keysym_t *syms; + size_t nsyms; + xkb_keysym_t keysym; + const char *utf8; +}; + #endif diff --git a/tools/compose.c b/tools/compose.c index 2b3ba643c..fd206b88d 100644 --- a/tools/compose.c +++ b/tools/compose.c @@ -29,6 +29,7 @@ #include #include "xkbcommon/xkbcommon.h" +#include "xkbcommon/xkbcommon-keysyms.h" #include "xkbcommon/xkbcommon-compose.h" static void @@ -44,6 +45,32 @@ usage(FILE *fp, char *progname) ); } +static void +compose_table_print_cb(struct xkb_compose_table_entry *entry, void *data) +{ + size_t nsyms; + const xkb_keysym_t *syms = xkb_compose_table_entry_lhs(entry, &nsyms); + char buf[128]; + for (size_t i = 0; i < nsyms; i++) { + xkb_keysym_get_name(syms[i], buf, sizeof(buf)); + printf("<%s>", buf); + if (i + 1 < nsyms) { + printf(" "); + } + } + printf(":"); + const char *utf8 = xkb_compose_table_entry_utf8(entry); + if (*utf8 != '\0') { + printf(" \"%s\"", utf8); + } + const xkb_keysym_t keysym = xkb_compose_table_entry_keysym(entry); + if (keysym != XKB_KEY_NoSymbol) { + xkb_keysym_get_name(keysym, buf, sizeof(buf)); + printf(" %s", buf); + } + printf("\n"); +} + int main(int argc, char *argv[]) { @@ -116,7 +143,7 @@ main(int argc, char *argv[]) goto out; } - printf("Compiled successfully from locale %s\n", locale); + xkb_compose_table_for_each(compose_table, compose_table_print_cb, NULL); out: xkb_compose_table_unref(compose_table); diff --git a/xkbcommon.map b/xkbcommon.map index 59ef97182..63a426d23 100644 --- a/xkbcommon.map +++ b/xkbcommon.map @@ -109,3 +109,11 @@ global: xkb_utf32_to_keysym; xkb_keymap_key_get_mods_for_level; } V_0.8.0; + +V_1.5.0 { +global: + xkb_compose_table_entry_lhs; + xkb_compose_table_entry_keysym; + xkb_compose_table_entry_utf8; + xkb_compose_table_for_each; +} V_1.0.0;