summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--src/keymap.c37
-rw-r--r--src/keymap.h2
-rw-r--r--src/xkbcomp/scanner.l32
-rw-r--r--src/xkbcomp/xkbcomp-priv.h4
-rw-r--r--src/xkbcomp/xkbcomp.c33
-rw-r--r--test/.gitignore1
-rw-r--r--test/buffercomp.c90
-rw-r--r--test/common.c15
-rw-r--r--test/test.h3
-rw-r--r--xkbcommon/xkbcommon.h14
11 files changed, 233 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 0cd357a..f7e7fb1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -124,6 +124,7 @@ TESTS = \
test/context \
test/rules-file \
test/stringcomp \
+ test/buffercomp \
test/log
TESTS_LDADD = libtest.la
@@ -134,6 +135,7 @@ test_context_LDADD = $(TESTS_LDADD)
test_rules_file_CFLAGS = $(AM_CFLAGS) -Wno-declaration-after-statement
test_rules_file_LDADD = $(TESTS_LDADD) -lrt
test_stringcomp_LDADD = $(TESTS_LDADD)
+test_buffercomp_LDADD = $(TESTS_LDADD)
test_log_LDADD = $(TESTS_LDADD)
test_rmlvo_to_kccgst_LDADD = $(TESTS_LDADD)
test_print_compiled_keymap_LDADD = $(TESTS_LDADD)
diff --git a/src/keymap.c b/src/keymap.c
index b468f94..3df183a 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -222,6 +222,43 @@ xkb_keymap_new_from_string(struct xkb_context *ctx,
}
XKB_EXPORT struct xkb_keymap *
+xkb_keymap_new_from_buffer(struct xkb_context *ctx,
+ const char *buffer, size_t length,
+ enum xkb_keymap_format format,
+ enum xkb_keymap_compile_flags flags)
+{
+ struct xkb_keymap *keymap;
+ const struct xkb_keymap_format_ops *ops;
+
+ ops = get_keymap_format_ops(format);
+ if (!ops || !ops->keymap_new_from_string) {
+ log_err_func(ctx, "unsupported keymap format: %d\n", format);
+ return NULL;
+ }
+
+ if (flags & ~(XKB_MAP_COMPILE_PLACEHOLDER)) {
+ log_err_func(ctx, "unrecognized flags: %#x\n", flags);
+ return NULL;
+ }
+
+ if (!buffer) {
+ log_err_func1(ctx, "no buffer specified\n");
+ return NULL;
+ }
+
+ keymap = xkb_keymap_new(ctx, format, flags);
+ if (!keymap)
+ return NULL;
+
+ if (!ops->keymap_new_from_buffer(keymap, buffer, length)) {
+ xkb_keymap_unref(keymap);
+ return NULL;
+ }
+
+ return keymap;
+}
+
+XKB_EXPORT struct xkb_keymap *
xkb_keymap_new_from_file(struct xkb_context *ctx,
FILE *file,
enum xkb_keymap_format format,
diff --git a/src/keymap.h b/src/keymap.h
index 12a2771..c6b884d 100644
--- a/src/keymap.h
+++ b/src/keymap.h
@@ -440,6 +440,8 @@ struct xkb_keymap_format_ops {
const struct xkb_rule_names *names);
bool (*keymap_new_from_string)(struct xkb_keymap *keymap,
const char *string);
+ bool (*keymap_new_from_buffer)(struct xkb_keymap *keymap,
+ const char *buffer, size_t length);
bool (*keymap_new_from_file)(struct xkb_keymap *keymap, FILE *file);
char *(*keymap_get_as_string)(struct xkb_keymap *keymap);
};
diff --git a/src/xkbcomp/scanner.l b/src/xkbcomp/scanner.l
index 5ccf3e9..f30462d 100644
--- a/src/xkbcomp/scanner.l
+++ b/src/xkbcomp/scanner.l
@@ -267,6 +267,38 @@ XkbParseString(struct xkb_context *ctx, const char *string,
return xkb_file;
}
+/*
+ * yy_scan_buffer() requires the last two bytes of \buf to be 0. These two bytes
+ * are not scanned. Other zero bytes in the buffer are scanned normally, though.
+ * Due to these terminating zeroes, \length must be greater than 2.
+ * Furthermore, the buffer must be writable and you cannot make any assumptions
+ * about it after the scanner finished.
+ * All this must be guaranteed by the caller of this function!
+ */
+XkbFile *
+XkbParseBuffer(struct xkb_context *ctx, char *buf, size_t length,
+ const char *file_name)
+{
+ yyscan_t scanner;
+ struct scanner_extra extra;
+ YY_BUFFER_STATE state;
+ XkbFile *xkb_file;
+
+ if (!init_scanner(&scanner, &extra, ctx, file_name))
+ return NULL;
+
+ xkb_file = NULL;
+ state = yy_scan_buffer(buf, length, scanner);
+ if (state) {
+ xkb_file = parse(ctx, scanner, NULL);
+ yy_delete_buffer(state, scanner);
+ }
+
+ clear_scanner(scanner);
+
+ return xkb_file;
+}
+
XkbFile *
XkbParseFile(struct xkb_context *ctx, FILE *file,
const char *file_name, const char *map)
diff --git a/src/xkbcomp/xkbcomp-priv.h b/src/xkbcomp/xkbcomp-priv.h
index 51c033f..4d421b5 100644
--- a/src/xkbcomp/xkbcomp-priv.h
+++ b/src/xkbcomp/xkbcomp-priv.h
@@ -48,6 +48,10 @@ XkbFile *
XkbParseString(struct xkb_context *ctx, const char *string,
const char *file_name);
+XkbFile *
+XkbParseBuffer(struct xkb_context *ctx, char *buf, size_t length,
+ const char *file_name);
+
void
FreeXkbFile(XkbFile *file);
diff --git a/src/xkbcomp/xkbcomp.c b/src/xkbcomp/xkbcomp.c
index cc4b3ef..b9a1b5f 100644
--- a/src/xkbcomp/xkbcomp.c
+++ b/src/xkbcomp/xkbcomp.c
@@ -114,6 +114,38 @@ text_v1_keymap_new_from_string(struct xkb_keymap *keymap, const char *string)
}
static bool
+text_v1_keymap_new_from_buffer(struct xkb_keymap *keymap,
+ const char *buffer, size_t length)
+{
+ bool ok;
+ XkbFile *xkb_file;
+ char *buf;
+
+ buf = malloc(length + 2);
+ if (!buf) {
+ log_err(keymap->ctx, "Cannot allocate memory for keymap\n");
+ return NULL;
+ }
+
+ /* yy_scan_buffer requires two terminating zero bytes */
+ memcpy(buf, buffer, length);
+ buf[length] = 0;
+ buf[length + 1] = 0;
+
+ xkb_file = XkbParseBuffer(keymap->ctx, buf, length + 2, "input");
+ if (!xkb_file) {
+ log_err(keymap->ctx, "Failed to parse input xkb file\n");
+ free(buf);
+ return NULL;
+ }
+
+ ok = compile_keymap_file(keymap, xkb_file);
+ FreeXkbFile(xkb_file);
+ free(buf);
+ return ok;
+}
+
+static bool
text_v1_keymap_new_from_file(struct xkb_keymap *keymap, FILE *file)
{
bool ok;
@@ -133,6 +165,7 @@ text_v1_keymap_new_from_file(struct xkb_keymap *keymap, FILE *file)
const struct xkb_keymap_format_ops text_v1_keymap_format_ops = {
.keymap_new_from_names = text_v1_keymap_new_from_names,
.keymap_new_from_string = text_v1_keymap_new_from_string,
+ .keymap_new_from_buffer = text_v1_keymap_new_from_buffer,
.keymap_new_from_file = text_v1_keymap_new_from_file,
.keymap_get_as_string = text_v1_keymap_get_as_string,
};
diff --git a/test/.gitignore b/test/.gitignore
index 5a0b89f..d4bb051 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -7,6 +7,7 @@ state
context
rules-file
stringcomp
+buffercomp
keyseq
log
interactive
diff --git a/test/buffercomp.c b/test/buffercomp.c
new file mode 100644
index 0000000..5cc1dbc
--- /dev/null
+++ b/test/buffercomp.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2009 Dan Nicholson
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "test.h"
+
+#define DATA_PATH "keymaps/stringcomp.data"
+
+int
+main(int argc, char *argv[])
+{
+ struct xkb_context *ctx = test_get_context(0);
+ struct xkb_keymap *keymap;
+ char *original, *dump;
+
+ assert(ctx);
+
+ /* Load in a prebuilt keymap, make sure we can compile it from memory,
+ * then compare it to make sure we get the same result when dumping it
+ * to a string. */
+ original = test_read_file(DATA_PATH);
+ assert(original);
+
+ keymap = test_compile_buffer(ctx, original, strlen(original));
+ assert(keymap);
+
+ dump = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT);
+ assert(dump);
+
+ if (!streq(original, dump)) {
+ fprintf(stderr,
+ "round-trip test failed: dumped map differs from original\n");
+ fprintf(stderr, "path to original file: %s\n",
+ test_get_path(DATA_PATH));
+ fprintf(stderr, "length: dumped %lu, original %lu\n",
+ (unsigned long) strlen(dump),
+ (unsigned long) strlen(original));
+ fprintf(stderr, "dumped map:\n");
+ fprintf(stderr, "%s\n", dump);
+ fflush(stderr);
+ assert(0);
+ }
+
+ free(original);
+ free(dump);
+ xkb_keymap_unref(keymap);
+
+ /* Make sure we can't (falsely claim to) compile an empty string. */
+ keymap = test_compile_buffer(ctx, "", 0);
+ assert(!keymap);
+
+ /* Make sure we can recompile our output for a normal keymap from rules. */
+ keymap = test_compile_rules(ctx, NULL, NULL,
+ "ru,ca,de,us", ",multix,neo,intl", NULL);
+ assert(keymap);
+ dump = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT);
+ assert(dump);
+ xkb_keymap_unref(keymap);
+ keymap = test_compile_buffer(ctx, dump, strlen(dump));
+ assert(keymap);
+ xkb_keymap_unref(keymap);
+ free(dump);
+
+ xkb_context_unref(ctx);
+
+ return 0;
+}
diff --git a/test/common.c b/test/common.c
index 6d6f25e..7b4ee00 100644
--- a/test/common.c
+++ b/test/common.c
@@ -261,6 +261,21 @@ test_compile_string(struct xkb_context *context, const char *string)
}
struct xkb_keymap *
+test_compile_buffer(struct xkb_context *context, const char *buf, size_t len)
+{
+ struct xkb_keymap *keymap;
+
+ keymap = xkb_keymap_new_from_buffer(context, buf, len,
+ XKB_KEYMAP_FORMAT_TEXT_V1, 0);
+ if (!keymap) {
+ fprintf(stderr, "Failed to compile keymap from memory buffer\n");
+ return NULL;
+ }
+
+ return keymap;
+}
+
+struct xkb_keymap *
test_compile_rules(struct xkb_context *context, const char *rules,
const char *model, const char *layout,
const char *variant, const char *options)
diff --git a/test/test.h b/test/test.h
index c39ef8d..804606e 100644
--- a/test/test.h
+++ b/test/test.h
@@ -70,6 +70,9 @@ struct xkb_keymap *
test_compile_string(struct xkb_context *context, const char *string);
struct xkb_keymap *
+test_compile_buffer(struct xkb_context *context, const char *buf, size_t len);
+
+struct xkb_keymap *
test_compile_rules(struct xkb_context *context, const char *rules,
const char *model, const char *layout, const char *variant,
const char *options);
diff --git a/xkbcommon/xkbcommon.h b/xkbcommon/xkbcommon.h
index ad758b8..a2aecfb 100644
--- a/xkbcommon/xkbcommon.h
+++ b/xkbcommon/xkbcommon.h
@@ -741,6 +741,20 @@ xkb_keymap_new_from_string(struct xkb_context *context, const char *string,
enum xkb_keymap_compile_flags flags);
/**
+ * Create a keymap from a memory buffer.
+ *
+ * This is just like xkb_keymap_new_from_string(), but takes a length argument
+ * so the input string does not have to be zero-terminated.
+ *
+ * @see xkb_keymap_new_from_string()
+ * @memberof xkb_keymap
+ */
+struct xkb_keymap *
+xkb_keymap_new_from_buffer(struct xkb_context *context, const char *buffer,
+ size_t length, enum xkb_keymap_format format,
+ enum xkb_keymap_compile_flags flags);
+
+/**
* Take a new reference on a keymap.
*
* @returns The passed in keymap.