Blame libxklavier/xklavier_config.c

Packit 7e555f
/*
Packit 7e555f
 * Copyright (C) 2002-2006 Sergey V. Udaltsov <svu@gnome.org>
Packit 7e555f
 *
Packit 7e555f
 * This library is free software; you can redistribute it and/or
Packit 7e555f
 * modify it under the terms of the GNU Lesser General Public
Packit 7e555f
 * License as published by the Free Software Foundation; either
Packit 7e555f
 * version 2 of the License, or (at your option) any later version.
Packit 7e555f
 *
Packit 7e555f
 * This library is distributed in the hope that it will be useful,
Packit 7e555f
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 7e555f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 7e555f
 * Lesser General Public License for more details.
Packit 7e555f
 *
Packit 7e555f
 * You should have received a copy of the GNU Lesser General Public
Packit 7e555f
 * License along with this library; if not, write to the
Packit 7e555f
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 7e555f
 * Boston, MA 02111-1307, USA.
Packit 7e555f
 */
Packit 7e555f
Packit 7e555f
#include <errno.h>
Packit 7e555f
#include <locale.h>
Packit 7e555f
#include <libintl.h>
Packit 7e555f
#include <stdio.h>
Packit 7e555f
#include <string.h>
Packit 7e555f
#include <sys/param.h>
Packit 7e555f
#include <sys/stat.h>
Packit 7e555f
Packit 7e555f
#include "config.h"
Packit 7e555f
Packit 7e555f
#include "xklavier_private.h"
Packit 7e555f
Packit 7e555f
static GObjectClass *parent_class = NULL;
Packit 7e555f
Packit 7e555f
static xmlXPathCompExprPtr models_xpath;
Packit 7e555f
static xmlXPathCompExprPtr layouts_xpath;
Packit 7e555f
static xmlXPathCompExprPtr option_groups_xpath;
Packit 7e555f
Packit 7e555f
static GRegex **xml_encode_regexen = NULL;
Packit 7e555f
static GRegex **xml_decode_regexen = NULL;
Packit 7e555f
static const char *xml_decode_regexen_str[] = { "<", ">", "&" };
Packit 7e555f
static const char *xml_encode_regexen_str[] = { "<", ">", "&" };
Packit 7e555f
Packit 7e555f
/* gettext domain for translations */
Packit 7e555f
#define XKB_DOMAIN "xkeyboard-config"
Packit 7e555f
Packit 7e555f
enum {
Packit 7e555f
	PROP_0,
Packit 7e555f
	PROP_ENGINE
Packit 7e555f
};
Packit 7e555f
Packit 7e555f
typedef struct {
Packit 7e555f
	gchar **patterns;
Packit 7e555f
	XklTwoConfigItemsProcessFunc func;
Packit 7e555f
	gpointer data;
Packit 7e555f
	gboolean country_matched;
Packit 7e555f
	gboolean language_matched;
Packit 7e555f
	const XklConfigItem *layout_item;
Packit 7e555f
} SearchParamType;
Packit 7e555f
Packit 7e555f
static gboolean
Packit 7e555f
xkl_xml_find_config_item_child(xmlNodePtr iptr, xmlNodePtr * ptr)
Packit 7e555f
{
Packit 7e555f
	/* 
Packit 7e555f
	 * Walking through the 1st level children of iptr
Packit 7e555f
	 * looking for the configItem
Packit 7e555f
	 */
Packit 7e555f
	if (iptr->type != XML_ELEMENT_NODE)
Packit 7e555f
		return FALSE;
Packit 7e555f
	*ptr = iptr->children;
Packit 7e555f
	while (*ptr != NULL) {
Packit 7e555f
		switch ((*ptr)->type) {
Packit 7e555f
		case XML_ELEMENT_NODE:
Packit 7e555f
			return !g_ascii_strcasecmp
Packit 7e555f
			    ((char *) (*ptr)->name, "configItem");
Packit 7e555f
		case XML_TEXT_NODE:
Packit 7e555f
		case XML_COMMENT_NODE:
Packit 7e555f
			(*ptr) = (*ptr)->next;
Packit 7e555f
			continue;
Packit 7e555f
		default:
Packit 7e555f
			return FALSE;
Packit 7e555f
		}
Packit 7e555f
		break;
Packit 7e555f
	}
Packit 7e555f
	return FALSE;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static xmlNodePtr
Packit 7e555f
xkl_find_element(xmlNodePtr ptr, const gchar * tag_name)
Packit 7e555f
{
Packit 7e555f
	xmlNodePtr found_element = NULL;
Packit 7e555f
Packit 7e555f
	/* Look through all siblings, trying to find a node with proper name */
Packit 7e555f
	while (ptr != NULL) {
Packit 7e555f
		char *node_name = (char *) ptr->name;
Packit 7e555f
		if (ptr->type != XML_TEXT_NODE) {
Packit 7e555f
			if (!g_ascii_strcasecmp(node_name, tag_name)) {
Packit 7e555f
				found_element = ptr;
Packit 7e555f
				break;
Packit 7e555f
			}
Packit 7e555f
		}
Packit 7e555f
		ptr = ptr->next;
Packit 7e555f
	}
Packit 7e555f
	return found_element;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static gboolean
Packit 7e555f
xkl_item_populate_optional_array(XklConfigItem * item, xmlNodePtr ptr,
Packit 7e555f
				 const gchar list_tag[],
Packit 7e555f
				 const gchar element_tag[],
Packit 7e555f
				 const gchar property_name[])
Packit 7e555f
{
Packit 7e555f
	xmlNodePtr top_list_element =
Packit 7e555f
	    xkl_find_element(ptr, list_tag), element_ptr;
Packit 7e555f
	gint n_elements, idx;
Packit 7e555f
	gchar **elements = NULL;
Packit 7e555f
Packit 7e555f
	if (top_list_element == NULL || top_list_element->children == NULL)
Packit 7e555f
		return FALSE;
Packit 7e555f
Packit 7e555f
	n_elements = 0;
Packit 7e555f
Packit 7e555f
	/* First, count countries */
Packit 7e555f
	element_ptr = top_list_element->children;
Packit 7e555f
	while (NULL !=
Packit 7e555f
	       (element_ptr =
Packit 7e555f
		xkl_find_element(element_ptr, element_tag))) {
Packit 7e555f
		n_elements++;
Packit 7e555f
		element_ptr = element_ptr->next;
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	if (n_elements == 0)
Packit 7e555f
		return FALSE;
Packit 7e555f
Packit 7e555f
	elements = g_new0(gchar *, n_elements + 1);
Packit 7e555f
	/* Then, actually, populate the list */
Packit 7e555f
	element_ptr = top_list_element->children;
Packit 7e555f
	for (idx = 0;
Packit 7e555f
	     NULL != (element_ptr =
Packit 7e555f
		      xkl_find_element(element_ptr, element_tag));
Packit 7e555f
	     element_ptr = element_ptr->next, idx++) {
Packit 7e555f
		elements[idx] =
Packit 7e555f
		    g_strdup((const char *) element_ptr->
Packit 7e555f
			     children->content);
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	g_object_set_data_full(G_OBJECT(item),
Packit 7e555f
			       property_name, elements, (GDestroyNotify)
Packit 7e555f
			       g_strfreev);
Packit 7e555f
	return TRUE;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
#include "libxml/parserInternals.h"
Packit 7e555f
Packit 7e555f
gboolean
Packit 7e555f
xkl_read_config_item(XklConfigRegistry * config, gint doc_index,
Packit 7e555f
		     xmlNodePtr iptr, XklConfigItem * item)
Packit 7e555f
{
Packit 7e555f
	xmlNodePtr name_element, ptr;
Packit 7e555f
	xmlNodePtr desc_element = NULL, short_desc_element =
Packit 7e555f
	    NULL, vendor_element = NULL;
Packit 7e555f
Packit 7e555f
	gchar *vendor = NULL, *translated = NULL, *escaped =
Packit 7e555f
	    NULL, *unescaped = NULL;
Packit 7e555f
Packit 7e555f
	gint i;
Packit 7e555f
Packit 7e555f
	*item->name = 0;
Packit 7e555f
	*item->short_description = 0;
Packit 7e555f
	*item->description = 0;
Packit 7e555f
Packit 7e555f
	g_object_set_data(G_OBJECT(item), XCI_PROP_VENDOR, NULL);
Packit 7e555f
	g_object_set_data(G_OBJECT(item), XCI_PROP_COUNTRY_LIST, NULL);
Packit 7e555f
	g_object_set_data(G_OBJECT(item), XCI_PROP_LANGUAGE_LIST, NULL);
Packit 7e555f
Packit 7e555f
	if (!xkl_xml_find_config_item_child(iptr, &ptr))
Packit 7e555f
		return FALSE;
Packit 7e555f
Packit 7e555f
	if (doc_index > 0)
Packit 7e555f
		g_object_set_data(G_OBJECT(item), XCI_PROP_EXTRA_ITEM,
Packit 7e555f
				  GINT_TO_POINTER(TRUE));
Packit 7e555f
Packit 7e555f
	ptr = ptr->children;
Packit 7e555f
Packit 7e555f
	if (ptr->type == XML_TEXT_NODE)
Packit 7e555f
		ptr = ptr->next;
Packit 7e555f
	name_element = ptr;
Packit 7e555f
	ptr = ptr->next;
Packit 7e555f
Packit 7e555f
	short_desc_element = xkl_find_element(ptr, XML_TAG_SHORT_DESCR);
Packit 7e555f
	desc_element = xkl_find_element(ptr, XML_TAG_DESCR);
Packit 7e555f
	vendor_element = xkl_find_element(ptr, XML_TAG_VENDOR);
Packit 7e555f
Packit 7e555f
	if (name_element != NULL && name_element->children != NULL)
Packit 7e555f
		strncat(item->name,
Packit 7e555f
			(char *) name_element->children->content,
Packit 7e555f
			XKL_MAX_CI_NAME_LENGTH - 1);
Packit 7e555f
Packit 7e555f
	if (short_desc_element != NULL
Packit 7e555f
	    && short_desc_element->children != NULL) {
Packit 7e555f
		strncat(item->short_description,
Packit 7e555f
			dgettext(XKB_DOMAIN, (const char *)
Packit 7e555f
				 short_desc_element->children->content),
Packit 7e555f
			XKL_MAX_CI_SHORT_DESC_LENGTH - 1);
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	if (desc_element != NULL && desc_element->children != NULL) {
Packit 7e555f
		/* Convert all xml-related characters to XML form, otherwise dgettext won't find the translation 
Packit 7e555f
		 * The conversion is not using libxml2, because there are no handy functions in API */
Packit 7e555f
		translated =
Packit 7e555f
		    g_strdup((gchar *) desc_element->children->content);
Packit 7e555f
		for (i =
Packit 7e555f
		     sizeof(xml_encode_regexen_str) /
Packit 7e555f
		     sizeof(xml_encode_regexen_str[0]); --i >= 0;) {
Packit 7e555f
			escaped =
Packit 7e555f
			    g_regex_replace(xml_encode_regexen[i],
Packit 7e555f
					    translated, -1, 0,
Packit 7e555f
					    xml_decode_regexen_str[i], 0,
Packit 7e555f
					    NULL);
Packit 7e555f
			g_free(translated);
Packit 7e555f
			translated = escaped;
Packit 7e555f
		}
Packit 7e555f
		escaped = translated;
Packit 7e555f
Packit 7e555f
		/* Do the translation! */
Packit 7e555f
		translated =
Packit 7e555f
		    g_strdup(dgettext(XKB_DOMAIN, (const char *) escaped));
Packit 7e555f
		g_free(escaped);
Packit 7e555f
Packit 7e555f
		/* Convert all XML entities back to normal form */
Packit 7e555f
		for (i =
Packit 7e555f
		     sizeof(xml_decode_regexen_str) /
Packit 7e555f
		     sizeof(xml_decode_regexen_str[0]); --i >= 0;) {
Packit 7e555f
			unescaped =
Packit 7e555f
			    g_regex_replace(xml_decode_regexen[i],
Packit 7e555f
					    translated, -1, 0,
Packit 7e555f
					    xml_encode_regexen_str[i], 0,
Packit 7e555f
					    NULL);
Packit 7e555f
			g_free(translated);
Packit 7e555f
			translated = unescaped;
Packit 7e555f
		}
Packit 7e555f
		strncat(item->description,
Packit 7e555f
			translated, XKL_MAX_CI_DESC_LENGTH - 1);
Packit 7e555f
		g_free(translated);
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	if (vendor_element != NULL && vendor_element->children != NULL) {
Packit 7e555f
		vendor =
Packit 7e555f
		    g_strdup((const char *) vendor_element->children->
Packit 7e555f
			     content);
Packit 7e555f
		g_object_set_data_full(G_OBJECT(item), XCI_PROP_VENDOR,
Packit 7e555f
				       vendor, g_free);
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	xkl_item_populate_optional_array(item, ptr, XML_TAG_COUNTRY_LIST,
Packit 7e555f
					 XML_TAG_ISO3166ID,
Packit 7e555f
					 XCI_PROP_COUNTRY_LIST);
Packit 7e555f
	xkl_item_populate_optional_array(item, ptr, XML_TAG_LANGUAGE_LIST,
Packit 7e555f
					 XML_TAG_ISO639ID,
Packit 7e555f
					 XCI_PROP_LANGUAGE_LIST);
Packit 7e555f
Packit 7e555f
	return TRUE;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static void
Packit 7e555f
xkl_config_registry_foreach_in_nodeset(XklConfigRegistry * config,
Packit 7e555f
				       GSList ** processed_ids,
Packit 7e555f
				       gint doc_index, xmlNodeSetPtr nodes,
Packit 7e555f
				       XklConfigItemProcessFunc func,
Packit 7e555f
				       gpointer data)
Packit 7e555f
{
Packit 7e555f
	gint i;
Packit 7e555f
	if (nodes != NULL) {
Packit 7e555f
		xmlNodePtr *pnode = nodes->nodeTab;
Packit 7e555f
		XklConfigItem *ci = xkl_config_item_new();
Packit 7e555f
		for (i = nodes->nodeNr; --i >= 0;) {
Packit 7e555f
			if (xkl_read_config_item
Packit 7e555f
			    (config, doc_index, *pnode, ci)) {
Packit 7e555f
				if (g_slist_find_custom
Packit 7e555f
				    (*processed_ids, ci->name,
Packit 7e555f
				     (GCompareFunc) g_ascii_strcasecmp) ==
Packit 7e555f
				    NULL) {
Packit 7e555f
					func(config, ci, data);
Packit 7e555f
					*processed_ids =
Packit 7e555f
					    g_slist_append(*processed_ids,
Packit 7e555f
							   g_strdup
Packit 7e555f
							   (ci->name));
Packit 7e555f
				}
Packit 7e555f
			}
Packit 7e555f
Packit 7e555f
			pnode++;
Packit 7e555f
		}
Packit 7e555f
		g_object_unref(G_OBJECT(ci));
Packit 7e555f
	}
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_registry_foreach_in_xpath(XklConfigRegistry * config,
Packit 7e555f
				     xmlXPathCompExprPtr
Packit 7e555f
				     xpath_comp_expr,
Packit 7e555f
				     XklConfigItemProcessFunc func,
Packit 7e555f
				     gpointer data)
Packit 7e555f
{
Packit 7e555f
	xmlXPathObjectPtr xpath_obj;
Packit 7e555f
	gint di;
Packit 7e555f
	GSList *processed_ids = NULL;
Packit 7e555f
Packit 7e555f
	if (!xkl_config_registry_is_initialized(config))
Packit 7e555f
		return;
Packit 7e555f
Packit 7e555f
	for (di = 0; di < XKL_NUMBER_OF_REGISTRY_DOCS; di++) {
Packit 7e555f
		xmlXPathContextPtr xmlctxt =
Packit 7e555f
		    xkl_config_registry_priv(config, xpath_contexts[di]);
Packit 7e555f
		if (xmlctxt == NULL)
Packit 7e555f
			continue;
Packit 7e555f
Packit 7e555f
		xpath_obj = xmlXPathCompiledEval(xpath_comp_expr, xmlctxt);
Packit 7e555f
		if (xpath_obj == NULL)
Packit 7e555f
			continue;
Packit 7e555f
Packit 7e555f
		xkl_config_registry_foreach_in_nodeset(config,
Packit 7e555f
						       &processed_ids, di,
Packit 7e555f
						       xpath_obj->
Packit 7e555f
						       nodesetval, func,
Packit 7e555f
						       data);
Packit 7e555f
		xmlXPathFreeObject(xpath_obj);
Packit 7e555f
	}
Packit 7e555f
	g_slist_foreach(processed_ids, (GFunc) g_free, NULL);
Packit 7e555f
	g_slist_free(processed_ids);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_registry_foreach_in_xpath_with_param(XklConfigRegistry
Packit 7e555f
						* config,
Packit 7e555f
						const gchar *
Packit 7e555f
						format,
Packit 7e555f
						const gchar *
Packit 7e555f
						value,
Packit 7e555f
						XklConfigItemProcessFunc
Packit 7e555f
						func, gpointer data)
Packit 7e555f
{
Packit 7e555f
	char xpath_expr[1024];
Packit 7e555f
	xmlXPathObjectPtr xpath_obj;
Packit 7e555f
	gint di;
Packit 7e555f
	GSList *processed_ids = NULL;
Packit 7e555f
Packit 7e555f
	if (!xkl_config_registry_is_initialized(config))
Packit 7e555f
		return;
Packit 7e555f
Packit 7e555f
	g_snprintf(xpath_expr, sizeof xpath_expr, format, value);
Packit 7e555f
Packit 7e555f
	for (di = 0; di < XKL_NUMBER_OF_REGISTRY_DOCS; di++) {
Packit 7e555f
		xmlXPathContextPtr xmlctxt =
Packit 7e555f
		    xkl_config_registry_priv(config, xpath_contexts[di]);
Packit 7e555f
		if (xmlctxt == NULL)
Packit 7e555f
			continue;
Packit 7e555f
Packit 7e555f
		xpath_obj =
Packit 7e555f
		    xmlXPathEval((unsigned char *) xpath_expr, xmlctxt);
Packit 7e555f
		if (xpath_obj == NULL)
Packit 7e555f
			continue;
Packit 7e555f
Packit 7e555f
		xkl_config_registry_foreach_in_nodeset(config,
Packit 7e555f
						       &processed_ids, di,
Packit 7e555f
						       xpath_obj->
Packit 7e555f
						       nodesetval, func,
Packit 7e555f
						       data);
Packit 7e555f
		xmlXPathFreeObject(xpath_obj);
Packit 7e555f
	}
Packit 7e555f
	g_slist_foreach(processed_ids, (GFunc) g_free, NULL);
Packit 7e555f
	g_slist_free(processed_ids);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static gboolean
Packit 7e555f
xkl_config_registry_find_object(XklConfigRegistry * config,
Packit 7e555f
				const gchar * format,
Packit 7e555f
				const gchar * arg1,
Packit 7e555f
				XklConfigItem * pitem /* in/out */ ,
Packit 7e555f
				xmlNodePtr * pnode /* out */ )
Packit 7e555f
{
Packit 7e555f
	xmlXPathObjectPtr xpath_obj;
Packit 7e555f
	xmlNodeSetPtr nodes;
Packit 7e555f
	gboolean rv = FALSE;
Packit 7e555f
	gchar xpath_expr[1024];
Packit 7e555f
	gint di;
Packit 7e555f
Packit 7e555f
	if (!xkl_config_registry_is_initialized(config))
Packit 7e555f
		return FALSE;
Packit 7e555f
Packit 7e555f
	g_snprintf(xpath_expr, sizeof xpath_expr, format, arg1,
Packit 7e555f
		   pitem->name);
Packit 7e555f
Packit 7e555f
	for (di = 0; di < XKL_NUMBER_OF_REGISTRY_DOCS; di++) {
Packit 7e555f
		xmlXPathContextPtr xmlctxt =
Packit 7e555f
		    xkl_config_registry_priv(config, xpath_contexts[di]);
Packit 7e555f
		if (xmlctxt == NULL)
Packit 7e555f
			continue;
Packit 7e555f
Packit 7e555f
		xpath_obj =
Packit 7e555f
		    xmlXPathEval((unsigned char *) xpath_expr, xmlctxt);
Packit 7e555f
		if (xpath_obj == NULL)
Packit 7e555f
			continue;
Packit 7e555f
Packit 7e555f
		nodes = xpath_obj->nodesetval;
Packit 7e555f
		if (nodes != NULL && nodes->nodeTab != NULL
Packit 7e555f
		    && nodes->nodeNr > 0) {
Packit 7e555f
			rv = xkl_read_config_item(config, di,
Packit 7e555f
						  nodes->nodeTab[0],
Packit 7e555f
						  pitem);
Packit 7e555f
			if (pnode != NULL) {
Packit 7e555f
				*pnode = *nodes->nodeTab;
Packit 7e555f
			}
Packit 7e555f
		}
Packit 7e555f
Packit 7e555f
		xmlXPathFreeObject(xpath_obj);
Packit 7e555f
	}
Packit 7e555f
	return rv;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gchar *
Packit 7e555f
xkl_config_rec_merge_layouts(const XklConfigRec * data)
Packit 7e555f
{
Packit 7e555f
	return xkl_strings_concat_comma_separated(data->layouts);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gchar *
Packit 7e555f
xkl_config_rec_merge_variants(const XklConfigRec * data)
Packit 7e555f
{
Packit 7e555f
	return xkl_strings_concat_comma_separated(data->variants);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gchar *
Packit 7e555f
xkl_config_rec_merge_options(const XklConfigRec * data)
Packit 7e555f
{
Packit 7e555f
	return xkl_strings_concat_comma_separated(data->options);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gchar *
Packit 7e555f
xkl_strings_concat_comma_separated(gchar ** array)
Packit 7e555f
{
Packit 7e555f
	if (array) {
Packit 7e555f
		return g_strjoinv(",", array);
Packit 7e555f
	} else {
Packit 7e555f
		return g_strdup("");
Packit 7e555f
	}
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_rec_split_layouts(XklConfigRec * data, const gchar * merged)
Packit 7e555f
{
Packit 7e555f
	xkl_strings_split_comma_separated(&data->layouts, merged);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_rec_split_variants(XklConfigRec * data, const gchar * merged)
Packit 7e555f
{
Packit 7e555f
	xkl_strings_split_comma_separated(&data->variants, merged);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_rec_split_options(XklConfigRec * data, const gchar * merged)
Packit 7e555f
{
Packit 7e555f
	xkl_strings_split_comma_separated(&data->options, merged);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_strings_split_comma_separated(gchar *** array, const gchar * merged)
Packit 7e555f
{
Packit 7e555f
	*array = g_strsplit(merged, ",", 0);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gchar *
Packit 7e555f
xkl_engine_get_ruleset_name(XklEngine * engine,
Packit 7e555f
			    const gchar default_ruleset[])
Packit 7e555f
{
Packit 7e555f
	static gchar rules_set_name[1024] = "";
Packit 7e555f
	if (!rules_set_name[0]) {
Packit 7e555f
		/* first call */
Packit 7e555f
		gchar *rf = NULL;
Packit 7e555f
		if (!xkl_config_rec_get_from_root_window_property
Packit 7e555f
		    (NULL,
Packit 7e555f
		     xkl_engine_priv(engine, base_config_atom),
Packit 7e555f
		     &rf, engine) || (rf == NULL)) {
Packit 7e555f
			g_strlcpy(rules_set_name, default_ruleset,
Packit 7e555f
				  sizeof rules_set_name);
Packit 7e555f
			xkl_debug(100,
Packit 7e555f
				  "Using default rules set: [%s]\n",
Packit 7e555f
				  rules_set_name);
Packit 7e555f
			return rules_set_name;
Packit 7e555f
		}
Packit 7e555f
		g_strlcpy(rules_set_name, rf, sizeof rules_set_name);
Packit 7e555f
		g_free(rf);
Packit 7e555f
	}
Packit 7e555f
	xkl_debug(100, "Rules set: [%s]\n", rules_set_name);
Packit 7e555f
	return rules_set_name;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
XklConfigRegistry *
Packit 7e555f
xkl_config_registry_get_instance(XklEngine * engine)
Packit 7e555f
{
Packit 7e555f
	XklConfigRegistry *config;
Packit 7e555f
Packit 7e555f
	if (!engine) {
Packit 7e555f
		xkl_debug(10,
Packit 7e555f
			  "xkl_config_registry_get_instance : engine is NULL ?\n");
Packit 7e555f
		return NULL;
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	config =
Packit 7e555f
	    XKL_CONFIG_REGISTRY(g_object_new
Packit 7e555f
				(xkl_config_registry_get_type(),
Packit 7e555f
				 "engine", engine, NULL));
Packit 7e555f
Packit 7e555f
	return config;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
/* We process descriptions as "leaf" elements - this is ok for base.xml*/
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_registry_load_from_file(XklConfigRegistry * config,
Packit 7e555f
				   const gchar * file_name, gint docidx)
Packit 7e555f
{
Packit 7e555f
	xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
Packit 7e555f
	xmlDocPtr doc;
Packit 7e555f
Packit 7e555f
	xkl_debug(100, "Loading XML registry from file %s\n", file_name);
Packit 7e555f
Packit 7e555f
	xmlSAX2InitDefaultSAXHandler(ctxt->sax, TRUE);
Packit 7e555f
Packit 7e555f
	doc = xkl_config_registry_priv(config, docs[docidx]) =
Packit 7e555f
	    xmlCtxtReadFile(ctxt, file_name, NULL, XML_PARSE_NOBLANKS);
Packit 7e555f
	xmlFreeParserCtxt(ctxt);
Packit 7e555f
Packit 7e555f
	if (doc == NULL) {
Packit 7e555f
		xkl_config_registry_priv(config, xpath_contexts[docidx]) =
Packit 7e555f
		    NULL;
Packit 7e555f
		xkl_last_error_message =
Packit 7e555f
		    "Could not parse primary XKB configuration registry";
Packit 7e555f
		return FALSE;
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	xkl_config_registry_priv(config, xpath_contexts[docidx]) =
Packit 7e555f
	    xmlXPathNewContext(doc);
Packit 7e555f
Packit 7e555f
	return TRUE;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_registry_load_helper(XklConfigRegistry * config,
Packit 7e555f
				const char default_ruleset[],
Packit 7e555f
				const char base_dir[],
Packit 7e555f
				gboolean if_extras_needed)
Packit 7e555f
{
Packit 7e555f
	struct stat stat_buf;
Packit 7e555f
	gchar file_name[MAXPATHLEN] = "";
Packit 7e555f
	XklEngine *engine = xkl_config_registry_get_engine(config);
Packit 7e555f
	gchar *rf = xkl_engine_get_ruleset_name(engine, default_ruleset);
Packit 7e555f
Packit 7e555f
	if (rf == NULL || rf[0] == '\0')
Packit 7e555f
		return FALSE;
Packit 7e555f
Packit 7e555f
	g_snprintf(file_name, sizeof file_name, "%s/%s.xml", base_dir, rf);
Packit 7e555f
Packit 7e555f
	if (stat(file_name, &stat_buf) != 0) {
Packit 7e555f
		xkl_debug(0, "Missing registry file %s\n", file_name);
Packit 7e555f
		xkl_last_error_message = "Missing registry file";
Packit 7e555f
		return FALSE;
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	if (!xkl_config_registry_load_from_file(config, file_name, 0))
Packit 7e555f
		return FALSE;
Packit 7e555f
Packit 7e555f
	if (!if_extras_needed)
Packit 7e555f
		return TRUE;
Packit 7e555f
Packit 7e555f
	g_snprintf(file_name, sizeof file_name, "%s/%s.extras.xml",
Packit 7e555f
		   base_dir, rf);
Packit 7e555f
Packit 7e555f
	/* no extras - ok, no problem */
Packit 7e555f
	if (stat(file_name, &stat_buf) != 0)
Packit 7e555f
		return TRUE;
Packit 7e555f
Packit 7e555f
	return xkl_config_registry_load_from_file(config, file_name, 1);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_registry_free(XklConfigRegistry * config)
Packit 7e555f
{
Packit 7e555f
	if (xkl_config_registry_is_initialized(config)) {
Packit 7e555f
		gint di;
Packit 7e555f
		for (di = 0; di < XKL_NUMBER_OF_REGISTRY_DOCS; di++) {
Packit 7e555f
			xmlXPathContextPtr xmlctxt =
Packit 7e555f
			    xkl_config_registry_priv(config,
Packit 7e555f
						     xpath_contexts[di]);
Packit 7e555f
			if (xmlctxt == NULL)
Packit 7e555f
				continue;
Packit 7e555f
Packit 7e555f
			xmlXPathFreeContext(xmlctxt);
Packit 7e555f
			xmlFreeDoc(xkl_config_registry_priv
Packit 7e555f
				   (config, docs[di]));
Packit 7e555f
			xkl_config_registry_priv(config,
Packit 7e555f
						 xpath_contexts[di]) =
Packit 7e555f
			    NULL;
Packit 7e555f
			xkl_config_registry_priv(config, docs[di]) = NULL;
Packit 7e555f
		}
Packit 7e555f
Packit 7e555f
	}
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_registry_foreach_model(XklConfigRegistry * config,
Packit 7e555f
				  XklConfigItemProcessFunc func,
Packit 7e555f
				  gpointer data)
Packit 7e555f
{
Packit 7e555f
	xkl_config_registry_foreach_in_xpath(config, models_xpath,
Packit 7e555f
					     func, data);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_registry_foreach_layout(XklConfigRegistry * config,
Packit 7e555f
				   XklConfigItemProcessFunc func,
Packit 7e555f
				   gpointer data)
Packit 7e555f
{
Packit 7e555f
	xkl_config_registry_foreach_in_xpath(config, layouts_xpath,
Packit 7e555f
					     func, data);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_registry_foreach_layout_variant(XklConfigRegistry *
Packit 7e555f
					   config,
Packit 7e555f
					   const gchar *
Packit 7e555f
					   layout_name,
Packit 7e555f
					   XklConfigItemProcessFunc
Packit 7e555f
					   func, gpointer data)
Packit 7e555f
{
Packit 7e555f
	xkl_config_registry_foreach_in_xpath_with_param(config,
Packit 7e555f
							XKBCR_VARIANT_PATH
Packit 7e555f
							"[../../configItem/name = '%s']",
Packit 7e555f
							layout_name,
Packit 7e555f
							func, data);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_registry_foreach_option_group(XklConfigRegistry *
Packit 7e555f
					 config,
Packit 7e555f
					 XklConfigItemProcessFunc
Packit 7e555f
					 func, gpointer data)
Packit 7e555f
{
Packit 7e555f
	xmlXPathObjectPtr xpath_obj;
Packit 7e555f
	gint di, j;
Packit 7e555f
	GSList *processed_ids = NULL;
Packit 7e555f
Packit 7e555f
	if (!xkl_config_registry_is_initialized(config))
Packit 7e555f
		return;
Packit 7e555f
Packit 7e555f
	for (di = 0; di < XKL_NUMBER_OF_REGISTRY_DOCS; di++) {
Packit 7e555f
		xmlNodeSetPtr nodes;
Packit 7e555f
		xmlNodePtr *pnode;
Packit 7e555f
		XklConfigItem *ci;
Packit 7e555f
Packit 7e555f
		xmlXPathContextPtr xmlctxt =
Packit 7e555f
		    xkl_config_registry_priv(config, xpath_contexts[di]);
Packit 7e555f
		if (xmlctxt == NULL)
Packit 7e555f
			continue;
Packit 7e555f
Packit 7e555f
		xpath_obj =
Packit 7e555f
		    xmlXPathCompiledEval(option_groups_xpath, xmlctxt);
Packit 7e555f
		if (xpath_obj == NULL)
Packit 7e555f
			continue;
Packit 7e555f
Packit 7e555f
		nodes = xpath_obj->nodesetval;
Packit 7e555f
		pnode = nodes->nodeTab;
Packit 7e555f
		ci = xkl_config_item_new();
Packit 7e555f
		for (j = nodes->nodeNr; --j >= 0;) {
Packit 7e555f
Packit 7e555f
			if (xkl_read_config_item(config, di, *pnode, ci)) {
Packit 7e555f
				if (g_slist_find_custom
Packit 7e555f
				    (processed_ids, ci->name,
Packit 7e555f
				     (GCompareFunc) g_ascii_strcasecmp) ==
Packit 7e555f
				    NULL) {
Packit 7e555f
					gboolean allow_multisel = TRUE;
Packit 7e555f
					xmlChar *sallow_multisel =
Packit 7e555f
					    xmlGetProp(*pnode,
Packit 7e555f
						       (unsigned char *)
Packit 7e555f
						       XCI_PROP_ALLOW_MULTIPLE_SELECTION);
Packit 7e555f
					if (sallow_multisel != NULL) {
Packit 7e555f
						allow_multisel =
Packit 7e555f
						    !g_ascii_strcasecmp
Packit 7e555f
						    ("true", (char *)
Packit 7e555f
						     sallow_multisel);
Packit 7e555f
						xmlFree(sallow_multisel);
Packit 7e555f
						g_object_set_data(G_OBJECT
Packit 7e555f
								  (ci),
Packit 7e555f
								  XCI_PROP_ALLOW_MULTIPLE_SELECTION,
Packit 7e555f
								  GINT_TO_POINTER
Packit 7e555f
								  (allow_multisel));
Packit 7e555f
					}
Packit 7e555f
Packit 7e555f
					func(config, ci, data);
Packit 7e555f
					processed_ids =
Packit 7e555f
					    g_slist_append(processed_ids,
Packit 7e555f
							   g_strdup
Packit 7e555f
							   (ci->name));
Packit 7e555f
				}
Packit 7e555f
			}
Packit 7e555f
Packit 7e555f
			pnode++;
Packit 7e555f
		}
Packit 7e555f
		g_object_unref(G_OBJECT(ci));
Packit 7e555f
		xmlXPathFreeObject(xpath_obj);
Packit 7e555f
	}
Packit 7e555f
	g_slist_foreach(processed_ids, (GFunc) g_free, NULL);
Packit 7e555f
	g_slist_free(processed_ids);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_registry_foreach_option(XklConfigRegistry * config,
Packit 7e555f
				   const gchar *
Packit 7e555f
				   option_group_name,
Packit 7e555f
				   XklConfigItemProcessFunc func,
Packit 7e555f
				   gpointer data)
Packit 7e555f
{
Packit 7e555f
	xkl_config_registry_foreach_in_xpath_with_param(config,
Packit 7e555f
							XKBCR_OPTION_PATH
Packit 7e555f
							"[../configItem/name = '%s']",
Packit 7e555f
							option_group_name,
Packit 7e555f
							func, data);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static gboolean
Packit 7e555f
search_all(const gchar * haystack, gchar ** needles)
Packit 7e555f
{
Packit 7e555f
	/* match anything */
Packit 7e555f
	if (!needles || !*needles)
Packit 7e555f
		return TRUE;
Packit 7e555f
Packit 7e555f
	gchar *uchs = g_utf8_strup(haystack, -1);
Packit 7e555f
	do {
Packit 7e555f
		if (g_strstr_len(uchs, -1, *needles) == NULL) {
Packit 7e555f
			g_free(uchs);
Packit 7e555f
			return FALSE;
Packit 7e555f
		}
Packit 7e555f
		needles++;
Packit 7e555f
	} while (*needles);
Packit 7e555f
Packit 7e555f
	g_free(uchs);
Packit 7e555f
	return TRUE;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static gboolean
Packit 7e555f
if_country_matches_pattern(const XklConfigItem * item,
Packit 7e555f
			   gchar ** patterns, const gboolean check_name)
Packit 7e555f
{
Packit 7e555f
	const gchar *country_desc;
Packit 7e555f
	if (check_name) {
Packit 7e555f
		gchar *upper_name = g_ascii_strup(item->name, -1);
Packit 7e555f
		country_desc = xkl_get_country_name(upper_name);
Packit 7e555f
		g_free(upper_name);
Packit 7e555f
		xkl_debug(200, "Checking layout country: [%s]\n",
Packit 7e555f
			  country_desc);
Packit 7e555f
		if ((country_desc != NULL)
Packit 7e555f
		    && search_all(country_desc, patterns))
Packit 7e555f
			return TRUE;
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	gchar **countries = g_object_get_data(G_OBJECT(item),
Packit 7e555f
					      XCI_PROP_COUNTRY_LIST);
Packit 7e555f
	for (; countries && *countries; countries++) {
Packit 7e555f
		country_desc = xkl_get_country_name(*countries);
Packit 7e555f
		xkl_debug(200, "Checking country: [%s][%s]\n",
Packit 7e555f
			  *countries, country_desc);
Packit 7e555f
		if ((country_desc != NULL)
Packit 7e555f
		    && search_all(country_desc, patterns)) {
Packit 7e555f
			return TRUE;
Packit 7e555f
		}
Packit 7e555f
	}
Packit 7e555f
	return FALSE;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static gboolean
Packit 7e555f
if_language_matches_pattern(const XklConfigItem * item,
Packit 7e555f
			    gchar ** patterns, const gboolean check_name)
Packit 7e555f
{
Packit 7e555f
	const gchar *language_desc;
Packit 7e555f
	if (check_name) {
Packit 7e555f
		language_desc = xkl_get_language_name(item->name);
Packit 7e555f
		xkl_debug(200, "Checking layout language: [%s]\n",
Packit 7e555f
			  language_desc);
Packit 7e555f
		if ((language_desc != NULL)
Packit 7e555f
		    && search_all(language_desc, patterns))
Packit 7e555f
			return TRUE;
Packit 7e555f
	}
Packit 7e555f
	gchar **languages = g_object_get_data(G_OBJECT(item),
Packit 7e555f
					      XCI_PROP_LANGUAGE_LIST);
Packit 7e555f
	for (; languages && *languages; languages++) {
Packit 7e555f
		language_desc = xkl_get_language_name(*languages);
Packit 7e555f
		xkl_debug(200, "Checking language: [%s][%s]\n",
Packit 7e555f
			  *languages, language_desc);
Packit 7e555f
		if ((language_desc != NULL)
Packit 7e555f
		    && search_all(language_desc, patterns)) {
Packit 7e555f
			return TRUE;
Packit 7e555f
		}
Packit 7e555f
	}
Packit 7e555f
	return FALSE;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static void
Packit 7e555f
xkl_config_registry_search_by_pattern_in_variant(XklConfigRegistry *
Packit 7e555f
						 config,
Packit 7e555f
						 const XklConfigItem *
Packit 7e555f
						 item,
Packit 7e555f
						 SearchParamType *
Packit 7e555f
						 search_param)
Packit 7e555f
{
Packit 7e555f
	gboolean variant_matched = FALSE;
Packit 7e555f
	gchar *full_desc = g_strdup_printf("%s - %s",
Packit 7e555f
					   search_param->
Packit 7e555f
					   layout_item->description,
Packit 7e555f
					   item->description);
Packit 7e555f
Packit 7e555f
	xkl_debug(200, "Variant to check: [%s][%s]\n", item->name,
Packit 7e555f
		  item->description);
Packit 7e555f
Packit 7e555f
	if (search_all(full_desc, search_param->patterns))
Packit 7e555f
		variant_matched = TRUE;
Packit 7e555f
Packit 7e555f
	g_free(full_desc);
Packit 7e555f
Packit 7e555f
	if (!variant_matched) {
Packit 7e555f
		gchar **countries = g_object_get_data(G_OBJECT(item),
Packit 7e555f
						      XCI_PROP_COUNTRY_LIST);
Packit 7e555f
		if (countries && g_strv_length(countries) > 0) {
Packit 7e555f
			if (if_country_matches_pattern
Packit 7e555f
			    (item, search_param->patterns, FALSE))
Packit 7e555f
				variant_matched = TRUE;
Packit 7e555f
		} else {
Packit 7e555f
			if (search_param->country_matched)
Packit 7e555f
				variant_matched = TRUE;
Packit 7e555f
		}
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	if (!variant_matched) {
Packit 7e555f
		gchar **languages = g_object_get_data(G_OBJECT(item),
Packit 7e555f
						      XCI_PROP_LANGUAGE_LIST);
Packit 7e555f
		if (languages && g_strv_length(languages) > 0) {
Packit 7e555f
			if (if_language_matches_pattern
Packit 7e555f
			    (item, search_param->patterns, FALSE))
Packit 7e555f
				variant_matched = TRUE;
Packit 7e555f
		} else {
Packit 7e555f
			if (search_param->language_matched)
Packit 7e555f
				variant_matched = TRUE;
Packit 7e555f
		}
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	if (variant_matched)
Packit 7e555f
		(search_param->func) (config, search_param->layout_item,
Packit 7e555f
				      item, search_param->data);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static void
Packit 7e555f
xkl_config_registry_search_by_pattern_in_layout(XklConfigRegistry * config,
Packit 7e555f
						const XklConfigItem * item,
Packit 7e555f
						SearchParamType *
Packit 7e555f
						search_param)
Packit 7e555f
{
Packit 7e555f
	gchar *upper_name = g_ascii_strup(item->name, -1);
Packit 7e555f
Packit 7e555f
	xkl_debug(200, "Layout to check: [%s][%s]\n", item->name,
Packit 7e555f
		  item->description);
Packit 7e555f
Packit 7e555f
	search_param->country_matched =
Packit 7e555f
	    search_param->language_matched = FALSE;
Packit 7e555f
Packit 7e555f
	if (if_country_matches_pattern(item, search_param->patterns, TRUE))
Packit 7e555f
		search_param->country_matched = TRUE;
Packit 7e555f
	else if (if_language_matches_pattern
Packit 7e555f
		 (item, search_param->patterns, TRUE))
Packit 7e555f
		search_param->language_matched = TRUE;
Packit 7e555f
	else if (search_all(item->description, search_param->patterns))
Packit 7e555f
		search_param->language_matched = TRUE;
Packit 7e555f
Packit 7e555f
	if (search_param->country_matched
Packit 7e555f
	    || search_param->language_matched)
Packit 7e555f
		(search_param->func) (config, item, NULL,
Packit 7e555f
				      search_param->data);
Packit 7e555f
Packit 7e555f
	search_param->layout_item = item;
Packit 7e555f
Packit 7e555f
	xkl_config_registry_foreach_layout_variant(config, item->name,
Packit 7e555f
						   (XklConfigItemProcessFunc)
Packit 7e555f
						   xkl_config_registry_search_by_pattern_in_variant,
Packit 7e555f
						   search_param);
Packit 7e555f
Packit 7e555f
	g_free(upper_name);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_registry_search_by_pattern(XklConfigRegistry
Packit 7e555f
				      * config,
Packit 7e555f
				      const gchar *
Packit 7e555f
				      pattern,
Packit 7e555f
				      XklTwoConfigItemsProcessFunc
Packit 7e555f
				      func, gpointer data)
Packit 7e555f
{
Packit 7e555f
	xkl_debug(200, "Searching by pattern: [%s]\n", pattern);
Packit 7e555f
	gchar *upattern = pattern ? g_utf8_strup(pattern, -1) : NULL;
Packit 7e555f
	gchar **patterns = pattern ? g_strsplit(upattern, " ", -1) : NULL;
Packit 7e555f
	SearchParamType search_param = {
Packit 7e555f
		patterns, func, data
Packit 7e555f
	};
Packit 7e555f
	xkl_config_registry_foreach_layout(config, (XklConfigItemProcessFunc)
Packit 7e555f
					   xkl_config_registry_search_by_pattern_in_layout,
Packit 7e555f
					   &search_param);
Packit 7e555f
	g_strfreev(patterns);
Packit 7e555f
	g_free(upattern);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_registry_find_model(XklConfigRegistry *
Packit 7e555f
			       config, XklConfigItem * pitem /* in/out */ )
Packit 7e555f
{
Packit 7e555f
	return xkl_config_registry_find_object(config,
Packit 7e555f
					       XKBCR_MODEL_PATH
Packit 7e555f
					       "[configItem/name = '%s%s']",
Packit 7e555f
					       "", pitem, NULL);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_registry_find_layout(XklConfigRegistry *
Packit 7e555f
				config,
Packit 7e555f
				XklConfigItem * pitem /* in/out */ )
Packit 7e555f
{
Packit 7e555f
	return xkl_config_registry_find_object(config,
Packit 7e555f
					       XKBCR_LAYOUT_PATH
Packit 7e555f
					       "[configItem/name = '%s%s']",
Packit 7e555f
					       "", pitem, NULL);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_registry_find_variant(XklConfigRegistry *
Packit 7e555f
				 config,
Packit 7e555f
				 const char
Packit 7e555f
				 *layout_name,
Packit 7e555f
				 XklConfigItem * pitem /* in/out */ )
Packit 7e555f
{
Packit 7e555f
	return xkl_config_registry_find_object(config,
Packit 7e555f
					       XKBCR_VARIANT_PATH
Packit 7e555f
					       "[../../configItem/name = '%s' and configItem/name = '%s']",
Packit 7e555f
					       layout_name, pitem, NULL);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_registry_find_option_group(XklConfigRegistry * config, XklConfigItem * pitem	/* in/out */
Packit 7e555f
    )
Packit 7e555f
{
Packit 7e555f
	xmlNodePtr node = NULL;
Packit 7e555f
	gboolean rv = xkl_config_registry_find_object(config,
Packit 7e555f
						      XKBCR_GROUP_PATH
Packit 7e555f
						      "[configItem/name = '%s%s']",
Packit 7e555f
						      "", pitem, &node);
Packit 7e555f
	if (rv) {
Packit 7e555f
		xmlChar *val = xmlGetProp(node, (unsigned char *)
Packit 7e555f
					  XCI_PROP_ALLOW_MULTIPLE_SELECTION);
Packit 7e555f
		if (val != NULL) {
Packit 7e555f
			gboolean allow_multisel =
Packit 7e555f
			    !g_ascii_strcasecmp("true",
Packit 7e555f
						(char *) val);
Packit 7e555f
			g_object_set_data(G_OBJECT(pitem),
Packit 7e555f
					  XCI_PROP_ALLOW_MULTIPLE_SELECTION,
Packit 7e555f
					  GINT_TO_POINTER(allow_multisel));
Packit 7e555f
			xmlFree(val);
Packit 7e555f
		}
Packit 7e555f
	}
Packit 7e555f
	return rv;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_registry_find_option(XklConfigRegistry *
Packit 7e555f
				config,
Packit 7e555f
				const char
Packit 7e555f
				*option_group_name,
Packit 7e555f
				XklConfigItem * pitem /* in/out */ )
Packit 7e555f
{
Packit 7e555f
	return xkl_config_registry_find_object(config,
Packit 7e555f
					       XKBCR_OPTION_PATH
Packit 7e555f
					       "[../configItem/name = '%s' and configItem/name = '%s']",
Packit 7e555f
					       option_group_name,
Packit 7e555f
					       pitem, NULL);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
/*
Packit 7e555f
 * Calling through vtable
Packit 7e555f
 */
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_rec_activate(const XklConfigRec * data, XklEngine * engine)
Packit 7e555f
{
Packit 7e555f
	xkl_engine_ensure_vtable_inited(engine);
Packit 7e555f
	return xkl_engine_vcall(engine,
Packit 7e555f
				activate_config_rec) (engine, data);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_registry_load(XklConfigRegistry * config,
Packit 7e555f
			 gboolean if_extras_needed)
Packit 7e555f
{
Packit 7e555f
	XklEngine *engine;
Packit 7e555f
	xkl_config_registry_free(config);
Packit 7e555f
	engine = xkl_config_registry_get_engine(config);
Packit 7e555f
	xkl_engine_ensure_vtable_inited(engine);
Packit 7e555f
	return xkl_engine_vcall(engine,
Packit 7e555f
				load_config_registry) (config,
Packit 7e555f
						       if_extras_needed);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
gboolean
Packit 7e555f
xkl_config_rec_write_to_file(XklEngine * engine,
Packit 7e555f
			     const gchar * file_name,
Packit 7e555f
			     const XklConfigRec * data,
Packit 7e555f
			     const gboolean binary)
Packit 7e555f
{
Packit 7e555f
	if ((!binary
Packit 7e555f
	     && !(xkl_engine_priv(engine, features) &
Packit 7e555f
		  XKLF_CAN_OUTPUT_CONFIG_AS_ASCII))
Packit 7e555f
	    || (binary
Packit 7e555f
		&& !(xkl_engine_priv(engine, features) &
Packit 7e555f
		     XKLF_CAN_OUTPUT_CONFIG_AS_BINARY))) {
Packit 7e555f
		xkl_last_error_message =
Packit 7e555f
		    "Function not supported at backend";
Packit 7e555f
		return FALSE;
Packit 7e555f
	}
Packit 7e555f
	xkl_engine_ensure_vtable_inited(engine);
Packit 7e555f
	return xkl_engine_vcall(engine, write_config_rec_to_file)
Packit 7e555f
	    (engine, file_name, data, binary);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
void
Packit 7e555f
xkl_config_rec_dump(FILE * file, XklConfigRec * data)
Packit 7e555f
{
Packit 7e555f
	int j;
Packit 7e555f
	fprintf(file, "  model: [%s]\n", data->model);
Packit 7e555f
	fprintf(file, "  layouts:\n");
Packit 7e555f
#define OUTPUT_ARRZ(arrz) \
Packit 7e555f
  { \
Packit 7e555f
    gchar **p = data->arrz; \
Packit 7e555f
    fprintf( file, "  " #arrz ":\n" ); \
Packit 7e555f
    if ( p != NULL ) \
Packit 7e555f
      for( j = 0; *p != NULL; ) \
Packit 7e555f
        fprintf( file, "  %d: [%s]\n", j++, *p++ ); \
Packit 7e555f
  }
Packit 7e555f
	OUTPUT_ARRZ(layouts);
Packit 7e555f
	OUTPUT_ARRZ(variants);
Packit 7e555f
	OUTPUT_ARRZ(options);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
G_DEFINE_TYPE(XklConfigRegistry, xkl_config_registry, G_TYPE_OBJECT)
Packit 7e555f
static GObject *
Packit 7e555f
xkl_config_registry_constructor(GType type,
Packit 7e555f
				guint
Packit 7e555f
				n_construct_properties,
Packit 7e555f
				GObjectConstructParam *
Packit 7e555f
				construct_properties)
Packit 7e555f
{
Packit 7e555f
	GObject *obj;
Packit 7e555f
	XklConfigRegistry *config;
Packit 7e555f
	XklEngine *engine; {
Packit 7e555f
		/* Invoke parent constructor. */
Packit 7e555f
		g_type_class_peek(XKL_TYPE_CONFIG_REGISTRY);
Packit 7e555f
		obj =
Packit 7e555f
		    parent_class->constructor(type,
Packit 7e555f
					      n_construct_properties,
Packit 7e555f
					      construct_properties);
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
	config = XKL_CONFIG_REGISTRY(obj);
Packit 7e555f
	engine = XKL_ENGINE(g_value_peek_pointer
Packit 7e555f
			    (construct_properties[0].value));
Packit 7e555f
	xkl_config_registry_get_engine(config) = engine;
Packit 7e555f
	xkl_engine_ensure_vtable_inited(engine);
Packit 7e555f
	xkl_engine_vcall(engine, init_config_registry) (config);
Packit 7e555f
	return obj;
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static void
Packit 7e555f
xkl_config_registry_init(XklConfigRegistry * config)
Packit 7e555f
{
Packit 7e555f
	config->priv = g_new0(XklConfigRegistryPrivate, 1);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static void
Packit 7e555f
xkl_config_registry_set_property(GObject * object,
Packit 7e555f
				 guint property_id,
Packit 7e555f
				 const GValue * value, GParamSpec * pspec)
Packit 7e555f
{
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static void
Packit 7e555f
xkl_config_registry_get_property(GObject * object,
Packit 7e555f
				 guint property_id,
Packit 7e555f
				 GValue * value, GParamSpec * pspec)
Packit 7e555f
{
Packit 7e555f
	XklConfigRegistry *config = XKL_CONFIG_REGISTRY(object);
Packit 7e555f
	switch (property_id) {
Packit 7e555f
	case PROP_ENGINE:
Packit 7e555f
		g_value_set_pointer(value,
Packit 7e555f
				    xkl_config_registry_get_engine
Packit 7e555f
				    (config));
Packit 7e555f
		break;
Packit 7e555f
	}
Packit 7e555f
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static void
Packit 7e555f
xkl_config_registry_finalize(GObject * obj)
Packit 7e555f
{
Packit 7e555f
	XklConfigRegistry *config = (XklConfigRegistry *) obj;
Packit 7e555f
	xkl_config_registry_free(config);
Packit 7e555f
	g_free(config->priv);
Packit 7e555f
	G_OBJECT_CLASS(parent_class)->finalize(obj);
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
/* 
Packit 7e555f
 * This function is actually NEVER called.
Packit 7e555f
 * It is 'extern' just to avoid the compilation warnings
Packit 7e555f
 * TODO: add class cleanup
Packit 7e555f
 */
Packit 7e555f
extern void
Packit 7e555f
xkl_config_registry_class_term(XklConfigRegistryClass * klass)
Packit 7e555f
{
Packit 7e555f
	gint i;
Packit 7e555f
	if (models_xpath != NULL) {
Packit 7e555f
		xmlXPathFreeCompExpr(models_xpath);
Packit 7e555f
		models_xpath = NULL;
Packit 7e555f
	}
Packit 7e555f
	if (layouts_xpath != NULL) {
Packit 7e555f
		xmlXPathFreeCompExpr(layouts_xpath);
Packit 7e555f
		layouts_xpath = NULL;
Packit 7e555f
	}
Packit 7e555f
	if (option_groups_xpath != NULL) {
Packit 7e555f
		xmlXPathFreeCompExpr(option_groups_xpath);
Packit 7e555f
		option_groups_xpath = NULL;
Packit 7e555f
	}
Packit 7e555f
	if (xml_encode_regexen != NULL) {
Packit 7e555f
		for (i =
Packit 7e555f
		     sizeof(xml_encode_regexen_str) /
Packit 7e555f
		     sizeof(xml_encode_regexen_str[0]); --i >= 0;) {
Packit 7e555f
			g_regex_unref(xml_encode_regexen[i]);
Packit 7e555f
		}
Packit 7e555f
		g_free(xml_encode_regexen);
Packit 7e555f
		xml_encode_regexen = NULL;
Packit 7e555f
	}
Packit 7e555f
	if (xml_decode_regexen != NULL) {
Packit 7e555f
		for (i =
Packit 7e555f
		     sizeof(xml_decode_regexen_str) /
Packit 7e555f
		     sizeof(xml_decode_regexen_str[0]); --i >= 0;) {
Packit 7e555f
			g_regex_unref(xml_decode_regexen[i]);
Packit 7e555f
		}
Packit 7e555f
		g_free(xml_decode_regexen);
Packit 7e555f
		xml_decode_regexen = NULL;
Packit 7e555f
	}
Packit 7e555f
}
Packit 7e555f
Packit 7e555f
static void
Packit 7e555f
xkl_config_registry_class_init(XklConfigRegistryClass * klass)
Packit 7e555f
{
Packit 7e555f
	GObjectClass *object_class;
Packit 7e555f
	GParamSpec *engine_param_spec;
Packit 7e555f
	gint i;
Packit 7e555f
	object_class = (GObjectClass *) klass;
Packit 7e555f
	parent_class = g_type_class_peek_parent(object_class);
Packit 7e555f
	object_class->constructor = xkl_config_registry_constructor;
Packit 7e555f
	object_class->finalize = xkl_config_registry_finalize;
Packit 7e555f
	object_class->set_property = xkl_config_registry_set_property;
Packit 7e555f
	object_class->get_property = xkl_config_registry_get_property;
Packit 7e555f
	bind_textdomain_codeset(XKB_DOMAIN, "UTF-8");
Packit 7e555f
	engine_param_spec =
Packit 7e555f
	    g_param_spec_object("engine", "Engine", "XklEngine",
Packit 7e555f
				XKL_TYPE_ENGINE,
Packit 7e555f
				G_PARAM_CONSTRUCT_ONLY |
Packit 7e555f
				G_PARAM_READWRITE);
Packit 7e555f
	g_object_class_install_property(object_class, PROP_ENGINE,
Packit 7e555f
					engine_param_spec);
Packit 7e555f
	/* static stuff initialized */
Packit 7e555f
	xmlXPathInit();
Packit 7e555f
	models_xpath = xmlXPathCompile((unsigned char *)
Packit 7e555f
				       XKBCR_MODEL_PATH);
Packit 7e555f
	layouts_xpath = xmlXPathCompile((unsigned char *)
Packit 7e555f
					XKBCR_LAYOUT_PATH);
Packit 7e555f
	option_groups_xpath = xmlXPathCompile((unsigned char *)
Packit 7e555f
					      XKBCR_GROUP_PATH);
Packit 7e555f
	xml_encode_regexen =
Packit 7e555f
	    g_new0(GRegex *,
Packit 7e555f
		   sizeof(xml_encode_regexen_str) /
Packit 7e555f
		   sizeof(xml_encode_regexen_str[0]));
Packit 7e555f
	xml_decode_regexen =
Packit 7e555f
	    g_new0(GRegex *,
Packit 7e555f
		   sizeof(xml_decode_regexen_str) /
Packit 7e555f
		   sizeof(xml_decode_regexen_str[0]));
Packit 7e555f
	for (i =
Packit 7e555f
	     sizeof(xml_encode_regexen_str) /
Packit 7e555f
	     sizeof(xml_encode_regexen_str[0]); --i >= 0;) {
Packit 7e555f
		xml_encode_regexen[i] =
Packit 7e555f
		    g_regex_new(xml_encode_regexen_str[i], 0, 0, NULL);
Packit 7e555f
		xml_decode_regexen[i] =
Packit 7e555f
		    g_regex_new(xml_decode_regexen_str[i], 0, 0, NULL);
Packit 7e555f
	}
Packit 7e555f
}