Create path.h for the path.c functions
[profile/ivi/libxkbcommon.git] / src / xkbcomp / xkbcomp.c
index 4adb4be..68e180f 100644 (file)
@@ -24,171 +24,303 @@ sale, use or other dealings in this Software without prior written
 authorization from the authors.
 */
 
-#include <limits.h>
-#include "X11/extensions/XKBcommon.h"
-#include <X11/extensions/XKM.h>
-#include "XKBcommonint.h"
-#include "xkbcomp.h"
+#include "xkbcomp-priv.h"
+#include "rules.h"
 #include "parseutils.h"
-#include "utils.h"
+#include "path.h"
 
-#ifndef DFLT_XKB_CONFIG_ROOT
-#define DFLT_XKB_CONFIG_ROOT "/usr/share/X11/xkb"
-#endif
-
-/* Global debugging flags */
-unsigned int debugFlags = 0;
+/* Global warning level */
 unsigned int warningLevel = 0;
 
 #define ISEMPTY(str) (!(str) || (strlen(str) == 0))
 
 static XkbFile *
-XkbKeymapFileFromComponents(const XkbComponentNamesPtr ktcsg)
+XkbKeymapFileFromComponents(struct xkb_context *ctx,
+                            const struct xkb_component_names *ktcsg)
 {
-    XkbFile *keycodes, *types, *compat, *symbols, *geometry;
+    XkbFile *keycodes, *types, *compat, *symbols;
     IncludeStmt *inc;
 
-    if (!ktcsg) {
-        ERROR("no components to generate keymap file from\n");
-        return NULL;
-    }
-
     inc = IncludeCreate(ktcsg->keycodes, MergeDefault);
-    keycodes = CreateXKBFile(XkmKeyNamesIndex, NULL, (ParseCommon *)inc, 0);
+    keycodes = CreateXKBFile(ctx, XkmKeyNamesIndex, NULL,
+                             (ParseCommon *)inc, 0);
 
     inc = IncludeCreate(ktcsg->types, MergeDefault);
-    types = CreateXKBFile(XkmTypesIndex, NULL, (ParseCommon *)inc, 0);
+    types = CreateXKBFile(ctx, XkmTypesIndex, NULL,
+                          (ParseCommon *)inc, 0);
     AppendStmt(&keycodes->common, &types->common);
 
     inc = IncludeCreate(ktcsg->compat, MergeDefault);
-    compat = CreateXKBFile(XkmCompatMapIndex, NULL, (ParseCommon *)inc, 0);
+    compat = CreateXKBFile(ctx, XkmCompatMapIndex, NULL,
+                           (ParseCommon *)inc, 0);
     AppendStmt(&keycodes->common, &compat->common);
 
     inc = IncludeCreate(ktcsg->symbols, MergeDefault);
-    symbols = CreateXKBFile(XkmSymbolsIndex, NULL, (ParseCommon *)inc, 0);
+    symbols = CreateXKBFile(ctx, XkmSymbolsIndex, NULL,
+                            (ParseCommon *)inc, 0);
     AppendStmt(&keycodes->common, &symbols->common);
 
-    inc = IncludeCreate(ktcsg->geometry, MergeDefault);
-    geometry = CreateXKBFile(XkmGeometryIndex, NULL, (ParseCommon *)inc, 0);
-    AppendStmt(&keycodes->common, &geometry->common);
-
-    return CreateXKBFile(XkmKeymapFile, ktcsg->keymap, &keycodes->common, 0);
+    return CreateXKBFile(ctx, XkmKeymapFile,
+                         ktcsg->keymap ? ktcsg->keymap : strdup(""),
+                         &keycodes->common, 0);
 }
 
-static XkbComponentNamesPtr
-XkbComponentsFromRules(const char *rulesPath, const XkbRF_VarDefsPtr defs)
+static struct xkb_component_names *
+XkbComponentsFromRules(struct xkb_context *ctx,
+                       const char *rules,
+                       const XkbRF_VarDefsPtr defs)
 {
-    XkbRF_RulesPtr rules;
-    XkbComponentNamesPtr names = NULL;
+    FILE *rulesFile = NULL;
+    char *rulesPath = NULL;
+    XkbRF_RulesPtr loaded = NULL;
+    struct xkb_component_names * names = NULL;
+    int i;
+
+    rulesFile = XkbFindFileInPath(ctx, rules, XkmRulesFile, &rulesPath);
+    if (!rulesFile) {
+        ERROR("could not find \"%s\" rules in XKB path\n", rules);
+        ERROR("%d include paths searched:\n",
+              xkb_context_num_include_paths(ctx));
+        for (i = 0; i < xkb_context_num_include_paths(ctx); i++)
+            ERROR("\t%s\n", xkb_context_include_path_get(ctx, i));
+        return NULL;
+    }
 
-    if (!(rules = XkbcRF_Load((char *)rulesPath, NULL, False, True))) {
+    if (!(loaded = uTypedCalloc(1, XkbRF_RulesRec))) {
+        ERROR("failed to allocate XKB rules\n");
+        goto unwind_file;
+    }
+
+    if (!XkbcRF_LoadRules(rulesFile, loaded)) {
         ERROR("failed to load XKB rules \"%s\"\n", rulesPath);
-        goto fail;
+        goto unwind_file;
     }
 
-    if (!(names = _XkbTypedCalloc(1, XkbComponentNamesRec))) {
+    if (!(names = uTypedCalloc(1, struct xkb_component_names))) {
         ERROR("failed to allocate XKB components\n");
-        goto unwind_rules;
+        goto unwind_file;
     }
 
-    if (!XkbcRF_GetComponents(rules, defs, names)) {
-        _XkbFree(names->keymap);
-        _XkbFree(names->keycodes);
-        _XkbFree(names->types);
-        _XkbFree(names->compat);
-        _XkbFree(names->symbols);
-        _XkbFree(names->geometry);
-        _XkbFree(names);
+    if (!XkbcRF_GetComponents(loaded, defs, names)) {
+        free(names->keymap);
+        free(names->keycodes);
+        free(names->types);
+        free(names->compat);
+        free(names->symbols);
+        free(names);
         names = NULL;
         ERROR("no components returned from XKB rules \"%s\"\n", rulesPath);
     }
 
-unwind_rules:
-    XkbcRF_Free(rules, True);
-fail:
+unwind_file:
+    XkbcRF_Free(loaded);
+    if (rulesFile)
+        fclose(rulesFile);
+    free(rulesPath);
     return names;
 }
 
-XkbcDescPtr
-XkbcCompileKeymapFromRules(const char *rules, XkbRF_VarDefsPtr defs)
+_X_EXPORT struct xkb_keymap *
+xkb_map_new_from_names(struct xkb_context *ctx,
+                       const struct xkb_rule_names *rmlvo,
+                       enum xkb_map_compile_flags flags)
 {
-    char rulesPath[PATH_MAX];
-    int pathlen;
-    XkbComponentNamesPtr names;
-    XkbcDescPtr xkb;
+    XkbRF_VarDefsRec defs;
+    struct xkb_component_names *names;
+    struct xkb_keymap *keymap;
 
-    if (ISEMPTY(rules) || ISEMPTY(defs->layout)) {
+    if (!rmlvo || ISEMPTY(rmlvo->rules) || ISEMPTY(rmlvo->layout)) {
         ERROR("rules and layout required to generate XKB keymap\n");
         return NULL;
     }
 
-    pathlen = snprintf(rulesPath, sizeof(rulesPath),
-                       DFLT_XKB_CONFIG_ROOT "/rules/%s", rules);
-    if (pathlen >= sizeof(rulesPath)) {
-        ERROR("XKB rules path truncated\n");
-        return NULL;
-    }
+    defs.model = rmlvo->model;
+    defs.layout = rmlvo->layout;
+    defs.variant = rmlvo->variant;
+    defs.options = rmlvo->options;
 
-    names = XkbComponentsFromRules(rulesPath, defs);
+    names = XkbComponentsFromRules(ctx, rmlvo->rules, &defs);
     if (!names) {
         ERROR("failed to generate XKB components from rules \"%s\"\n",
-              rules);
+              rmlvo->rules);
         return NULL;
     }
 
-    xkb = XkbcCompileKeymapFromComponents(names);
+    keymap = xkb_map_new_from_kccgst(ctx, names, 0);
 
-    _XkbFree(names->keymap);
-    _XkbFree(names->keycodes);
-    _XkbFree(names->types);
-    _XkbFree(names->compat);
-    _XkbFree(names->symbols);
-    _XkbFree(names->geometry);
-    _XkbFree(names);
+    free(names->keymap);
+    free(names->keycodes);
+    free(names->types);
+    free(names->compat);
+    free(names->symbols);
+    free(names);
 
-    return xkb;
+    return keymap;
 }
 
-XkbcDescPtr
-XkbcCompileKeymapFromComponents(XkbComponentNamesPtr ktcsg)
+static XkbFile *
+XkbChooseMap(XkbFile *file, const char *name)
 {
-    XkbFile *file, *mapToUse;
-    XkbcDescPtr xkb;
+    XkbFile *map = file;
 
-    if (!(file = XkbKeymapFileFromComponents(ktcsg))) {
-        ERROR("failed to generate parsed XKB file from components\n");
-        goto fail;
-    }
+    /* map specified? */
+    if (name) {
+        while (map) {
+            if (map->name && strcmp(map->name, name) == 0)
+                break;
+            map = (XkbFile *) map->common.next;
+        }
 
-    /* Find map to use */
-    mapToUse = file;
-    if (file->common.next) {
-        for (; mapToUse; mapToUse = (XkbFile *)mapToUse->common.next) {
-            if (mapToUse->flags & XkbLC_Default)
+        if (!map)
+            ERROR("no map named \"%s\" in input file\n", name);
+    }
+    else if (file->common.next) {
+        /* look for map with XkbLC_Default flag. */
+        for (; map; map = (XkbFile *) map->common.next) {
+            if (map->flags & XkbLC_Default)
                 break;
         }
-        if (!mapToUse) {
-            mapToUse = file;
+
+        if (!map) {
+            map = file;
             WARN("no map specified, but components have several\n");
+            WARN("using the first defined map, \"%s\"\n",
+                 map->name ? map->name : "");
         }
     }
 
-    /* Compile the keyboard */
-    if (!(xkb = XkbcAllocKeyboard())) {
-        ERROR("could not allocate keyboard description\n");
-        goto unwind_file;
+    return map;
+}
+
+static struct xkb_keymap *
+compile_keymap(struct xkb_context *ctx, XkbFile *file)
+{
+    XkbFile *mapToUse;
+    struct xkb_keymap *keymap = NULL;
+
+    /* Find map to use */
+    mapToUse = XkbChooseMap(file, NULL);
+    if (!mapToUse)
+        goto err;
+
+    if (mapToUse->type != XkmKeymapFile) {
+        ERROR("file type %d not handled\n", mapToUse->type);
+        goto err;
     }
 
-    if (!CompileKeymap(mapToUse, xkb, MergeReplace)) {
-        ERROR("failed to compile keymap\n");
-        goto unwind_xkb;
+    keymap = CompileKeymap(ctx, mapToUse);
+    if (!keymap)
+        goto err;
+
+err:
+    FreeXKBFile(file);
+    return keymap;
+}
+
+_X_EXPORT struct xkb_keymap *
+xkb_map_new_from_kccgst(struct xkb_context *ctx,
+                        const struct xkb_component_names *kccgst,
+                        enum xkb_map_compile_flags flags)
+{
+    XkbFile *file;
+
+    if (!kccgst) {
+        ERROR("no components specified\n");
+        return NULL;
     }
 
-    return xkb;
-unwind_xkb:
-    XkbcFreeKeyboard(xkb, XkbAllComponentsMask, True);
-unwind_file:
-    /* XXX: here's where we would free the XkbFile */
-fail:
-    return NULL;
+    if (ISEMPTY(kccgst->keycodes)) {
+        ERROR("keycodes required to generate XKB keymap\n");
+        return NULL;
+    }
+
+    if (ISEMPTY(kccgst->compat)) {
+        ERROR("compat map required to generate XKB keymap\n");
+        return NULL;
+    }
+
+    if (ISEMPTY(kccgst->types)) {
+        ERROR("types required to generate XKB keymap\n");
+        return NULL;
+    }
+
+    if (ISEMPTY(kccgst->symbols)) {
+        ERROR("symbols required to generate XKB keymap\n");
+        return NULL;
+    }
+
+    if (!(file = XkbKeymapFileFromComponents(ctx, kccgst))) {
+        ERROR("failed to generate parsed XKB file from components\n");
+        return NULL;
+    }
+
+    return compile_keymap(ctx, file);
+}
+
+_X_EXPORT struct xkb_keymap *
+xkb_map_new_from_string(struct xkb_context *ctx,
+                        const char *string,
+                        enum xkb_keymap_format format,
+                        enum xkb_map_compile_flags flags)
+{
+    XkbFile *file;
+
+    if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
+        ERROR("unsupported keymap format %d\n", format);
+        return NULL;
+    }
+
+    if (!string) {
+        ERROR("no string specified to generate XKB keymap\n");
+        return NULL;
+    }
+
+    if (!XKBParseString(ctx, string, "input", &file)) {
+        ERROR("failed to parse input xkb file\n");
+        return NULL;
+    }
+
+    return compile_keymap(ctx, file);
+}
+
+_X_EXPORT struct xkb_keymap *
+xkb_map_new_from_file(struct xkb_context *ctx,
+                      FILE *file,
+                      enum xkb_keymap_format format,
+                      enum xkb_map_compile_flags flags)
+{
+    XkbFile *xkb_file;
+
+    if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
+        ERROR("unsupported keymap format %d\n", format);
+        return NULL;
+    }
+
+    if (!file) {
+        ERROR("no file specified to generate XKB keymap\n");
+        return NULL;
+    }
+
+    if (!XKBParseFile(ctx, file, "(unknown file)", &xkb_file)) {
+        ERROR("failed to parse input xkb file\n");
+        return NULL;
+    }
+
+    return compile_keymap(ctx, xkb_file);
+}
+
+_X_EXPORT struct xkb_keymap *
+xkb_map_ref(struct xkb_keymap *keymap)
+{
+    keymap->refcnt++;
+    return keymap;
+}
+
+_X_EXPORT void
+xkb_map_unref(struct xkb_keymap *keymap)
+{
+    if (--keymap->refcnt > 0)
+        return;
+
+    XkbcFreeKeyboard(keymap);
 }