diff options
-rw-r--r-- | console-client/Makefile | 1 | ||||
-rw-r--r-- | console-client/pc-kbd.c | 9 | ||||
-rw-r--r-- | console-client/xkb/compose.c | 173 |
3 files changed, 177 insertions, 6 deletions
diff --git a/console-client/Makefile b/console-client/Makefile index 7629e06a..c84eb7eb 100644 --- a/console-client/Makefile +++ b/console-client/Makefile @@ -118,6 +118,7 @@ XKB_UNITS = $(basename $(notdir $(XKB_SRCS))) pc_kbd.so.$(hurd-version): $(addsuffix _pic.o,$(XKB_UNITS)) pc-kbd-CFLAGS = -DXKB_SUPPORT -DXKB_DATA_DIR=\"$(XKB_BASE)\" $(X11_CFLAGS) $(foreach XKB_UNIT, $(XKB_UNITS), $(eval $(XKB_UNIT)-CFLAGS = $(X11_CFLAGS))) +compose-CFLAGS += -DDATADIR=\"$(datadir)\" pc_kbd-LDLIBS = $(X11_LIBS) install: $(XKB_BASE) $(addprefix $(XKB_BASE)/, $(XKB_DATA_FILES)) diff --git a/console-client/pc-kbd.c b/console-client/pc-kbd.c index fdc749d7..9999654f 100644 --- a/console-client/pc-kbd.c +++ b/console-client/pc-kbd.c @@ -1329,12 +1329,9 @@ pc_kbd_init (void **handle, int no_exit, int argc, char *argv[], int *next) xkb_repeat_delay = arguments.repeat_delay; xkb_repeat_interval = arguments.repeat_interval; - if (arguments.composefile) - { - err = read_composefile (arguments.composefile); - if (err) - return err; - } + err = read_composefile (arguments.composefile); + if (err) + return err; xkb_data_init (); err = xkb_load_layout (arguments.xkbdir, arguments.keymapfile, diff --git a/console-client/xkb/compose.c b/console-client/xkb/compose.c index e86b5799..65854e14 100644 --- a/console-client/xkb/compose.c +++ b/console-client/xkb/compose.c @@ -25,6 +25,10 @@ #include "xkb.h" #include <ctype.h> #include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <locale.h> +#include <assert.h> /* Tokens that can be recognised by the scanner. */ enum tokentype @@ -401,6 +405,171 @@ compose_symbols (symbol s) return -1; } +struct map_entry +{ + const char *left; + const char *right; +}; + +enum callback_result + { + NEXT, + DONE + }; + +typedef enum callback_result (*map_callback) (void *context, struct map_entry *entry); + +static error_t +map_iterate(const char *map_path, map_callback action, void *context) +{ + FILE *map; + char *buffer = NULL; + size_t buffer_size = 0; + size_t line_length = 0; + + assert (map_path != NULL); + assert (action != NULL); + + map = fopen (map_path, "r"); + + if (map == NULL) + return errno; + + while ( (line_length = getline (&buffer, &buffer_size, map)) != -1) + { + /* skips empty lines and comments */ + if (line_length < 1 || buffer[0] == '#') + continue; + else + { + struct map_entry entry = {NULL, NULL}; + char *end = buffer + line_length; + char *p = buffer; + + while (p != end && isspace(*p)) p++; + + if (p == end) + continue; + + entry.left = p; + + while (p != end && !isspace(*p)) p++; + + if (p != end) + { + *(p++) = 0; + while (p != end && isspace(*p)) p++; + + if (p != end) + { + entry.right = p; + while (p != end && !isspace(*p)) p++; + if (p != end) + *p = 0; + } + } + + if (action (context, &entry) == DONE) + break; + } + } + free (buffer); + fclose (map); + return 0; +} + +struct matcher_context +{ + char *value; + char *result; +}; + +static enum callback_result +match_left_set_right (void *context, struct map_entry *entry) +{ + struct matcher_context *ctx = (struct matcher_context *) context; + + if (strcmp (ctx->value, entry->left) == 0) + { + ctx->result = strdup (entry->right); + return DONE; + } + return NEXT; +} + +static enum callback_result +match_right_set_left (void *context, struct map_entry *entry) +{ + struct matcher_context *ctx = (struct matcher_context *) context; + + if (strcmp (ctx->value, entry->right) == 0) + { + ctx->result = strdup (entry->left); + return DONE; + } + return NEXT; +} + +/* Search for a compose file. + + According to Compose(5) man page the compose file searched in the + following locations: + - XCOMPOSEFILE variable. + - .XCompose at $HOME. + - System wide compose file for the current locale. */ +static char * +get_compose_file_for_locale() +{ + struct matcher_context context = { NULL }; + char *xcomposefile; + char *to_be_freed; + char *home; + int err; + + xcomposefile = getenv ("XCOMPOSEFILE"); + if (xcomposefile != NULL) + return strdup (xcomposefile); + + home = getenv ("HOME"); + if (home != NULL) + { + err = asprintf (&xcomposefile, "%s/.XCompose", home); + if (err != -1) + { + if (faccessat(AT_FDCWD, xcomposefile, R_OK, AT_EACCESS) == 0) + return xcomposefile; + else + { + free (xcomposefile); + /* TODO: check and report whether the compose file doesn't exist or + read permission was not granted to us. */ + } + } + } + + context.value = setlocale (LC_ALL, NULL); + map_iterate (DATADIR "/X11/locale/locale.alias", match_left_set_right, &context); + to_be_freed = context.result; + + if (context.result != NULL) + { + /* Current locale is an alias. Use the real name to index the database. */ + context.value = context.result; + } + context.result = NULL; + map_iterate (DATADIR "/X11/locale/compose.dir", match_right_set_left, &context); + free (to_be_freed); + + /* compose.dir contains relative paths to compose files. */ + to_be_freed = context.result; + err = asprintf (&context.result, DATADIR "/X11/locale/%s", context.result); + if (err == -1) + context.result = NULL; + + free (to_be_freed); + return context.result; +} + /* Read a Compose file. */ error_t read_composefile (char *composefn) @@ -408,6 +577,10 @@ read_composefile (char *composefn) FILE *cf; error_t err; + + if (composefn == NULL) + composefn = get_compose_file_for_locale (); + cf = fopen (composefn, "r"); if (cf == NULL) return errno; |