test/context \
test/rules-file \
test/stringcomp \
+ test/buffercomp \
test/log
TESTS_LDADD = libtest.la
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)
}
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,
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);
};
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)
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);
}
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;
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,
};
context
rules-file
stringcomp
+buffercomp
keyseq
log
interactive
--- /dev/null
+/*
+ * 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;
+}
}
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)
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);
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.