plug-ins/help/domain.[ch] removed these files...

2006-11-20  Michael Natterer  <mitch@gimp.org>

	* plug-ins/help/domain.[ch]
	* plug-ins/help/help.h: removed these files...

	* plug-ins/help/gimphelptypes.h
	* plug-ins/help/gimphelp.[ch]
	* plug-ins/help/gimphelpdomain.[ch]
	* plug-ins/help/gimphelpitem.[ch]
	* plug-ins/help/gimphelplocale.[ch]: ...completely chopped them
	and added a new private utility library. Soon to be used by the
	helpbrowser too.

	* plug-ins/help/Makefile.am
	* plug-ins/help/gimp-help-lookup.c
	* plug-ins/help/help.c: changed accordingly.
This commit is contained in:
Michael Natterer 2006-11-20 21:46:21 +00:00 committed by Michael Natterer
parent 73b1863a28
commit dc388813cb
14 changed files with 617 additions and 2425 deletions

View File

@ -1,3 +1,20 @@
2006-11-20 Michael Natterer <mitch@gimp.org>
* plug-ins/help/domain.[ch]
* plug-ins/help/help.h: removed these files...
* plug-ins/help/gimphelptypes.h
* plug-ins/help/gimphelp.[ch]
* plug-ins/help/gimphelpdomain.[ch]
* plug-ins/help/gimphelpitem.[ch]
* plug-ins/help/gimphelplocale.[ch]: ...completely chopped and
added as new private utility library. Soon to be used by the
helpbrowser too.
* plug-ins/help/Makefile.am
* plug-ins/help/gimp-help-lookup.c
* plug-ins/help/help.c: changed accordingly.
2006-11-20 Simon Budig <simon@gimp.org> 2006-11-20 Simon Budig <simon@gimp.org>
* app/vectors/gimpstroke.[ch] * app/vectors/gimpstroke.[ch]

View File

@ -1,5 +1,6 @@
## Process this file with automake to produce Makefile.in ## Process this file with automake to produce Makefile.in
libgimphelp = libgimphelp-$(GIMP_API_VERSION).la
libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
@ -13,17 +14,25 @@ AM_CPPFLAGS = -DDATADIR=\""$(gimpdatadir)"\"
AM_LDFLAGS = $(mwindows) AM_LDFLAGS = $(mwindows)
lib_LTLIBRARIES = libgimphelp-2.0.la
libgimphelp_2_0_la_SOURCES = \
gimphelptypes.h \
gimphelp.c \
gimphelp.h \
gimphelpdomain.c \
gimphelpdomain.h \
gimphelpitem.c \
gimphelpitem.h \
gimphelplocale.c \
gimphelplocale.h \
help.h
libexecdir = $(gimpplugindir)/plug-ins libexecdir = $(gimpplugindir)/plug-ins
libexec_PROGRAMS = help libexec_PROGRAMS = help
help_SOURCES = \ help_SOURCES = help.c
domain.c \
domain.h \
locales.c \
locales.h \
help.c \
help.h
INCLUDES = \ INCLUDES = \
-I$(top_srcdir) \ -I$(top_srcdir) \
@ -31,6 +40,7 @@ INCLUDES = \
-I$(includedir) -I$(includedir)
LDADD = \ LDADD = \
$(libgimphelp) \
$(libgimp) \ $(libgimp) \
$(libgimpcolor) \ $(libgimpcolor) \
$(libgimpbase) \ $(libgimpbase) \
@ -42,14 +52,9 @@ LDADD = \
noinst_PROGRAMS = gimp-help-lookup noinst_PROGRAMS = gimp-help-lookup
gimp_help_lookup_SOURCES = \ gimp_help_lookup_SOURCES = gimp-help-lookup.c
domain.c \
domain.h \
locales.c \
locales.h \
help.h \
gimp-help-lookup.c
gimp_help_lookup_LDADD = \ gimp_help_lookup_LDADD = \
$(libgimphelp) \
$(libgimpbase) \ $(libgimpbase) \
$(GLIB_LIBS) $(GLIB_LIBS)

View File

@ -1,732 +0,0 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* The GIMP Help plug-in
* Copyright (C) 1999-2004 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
* Henrik Brix Andersen <brix@gimp.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* This code is written so that it can also be compiled standalone.
* It shouldn't depend on libgimp.
*/
#include "config.h"
#include <string.h>
#include <glib.h>
#include "domain.h"
#include "help.h"
#ifdef DISABLE_NLS
#define _(String) (String)
#else
#include "libgimp/stdplugins-intl.h"
#endif
struct _HelpDomain
{
gchar *help_domain;
gchar *help_uri;
gchar *help_root;
GHashTable *help_locales;
};
typedef struct _HelpLocale HelpLocale;
struct _HelpLocale
{
gchar *locale_id;
GHashTable *help_id_mapping;
gchar *help_missing;
};
/* local function prototypes */
static HelpDomain * domain_new (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root);
static void domain_free (HelpDomain *domain);
static HelpLocale * domain_locale_new (const gchar *locale_id);
static void domain_locale_free (HelpLocale *locale);
static HelpLocale * domain_locale_lookup (HelpDomain *domain,
const gchar *locale_id);
static const gchar * domain_locale_map (HelpLocale *locale,
const gchar *help_id);
static gboolean domain_locale_parse (HelpDomain *domain,
HelpLocale *locale,
GError **error);
static void domain_error_set_message (GError **error,
const gchar *format,
const gchar *filename);
static gchar * filename_from_uri (const gchar *uri);
/* private variables */
static GHashTable *domain_hash = NULL;
/* public functions */
void
domain_register (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root)
{
g_return_if_fail (domain_name != NULL);
g_return_if_fail (domain_uri != NULL);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help: registering help domain \"%s\" with base uri \"%s\"\n",
domain_name, domain_uri);
#endif
if (! domain_hash)
domain_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) domain_free);
g_hash_table_insert (domain_hash,
g_strdup (domain_name),
domain_new (domain_name, domain_uri, domain_root));
}
HelpDomain *
domain_lookup (const gchar *domain_name)
{
g_return_val_if_fail (domain_name, NULL);
if (domain_hash)
return g_hash_table_lookup (domain_hash, domain_name);
return NULL;
}
gchar *
domain_map (HelpDomain *domain,
GList *help_locales,
const gchar *help_id)
{
HelpLocale *locale = NULL;
const gchar *ref = NULL;
GList *list;
g_return_val_if_fail (domain != NULL, NULL);
g_return_val_if_fail (help_locales != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
/* first pass: look for a reference matching the help_id */
for (list = help_locales; list && !ref; list = list->next)
{
locale = domain_locale_lookup (domain, (const gchar *) list->data);
ref = domain_locale_map (locale, help_id);
}
/* second pass: look for a fallback */
for (list = help_locales; list && !ref; list = list->next)
{
locale = domain_locale_lookup (domain, (const gchar *) list->data);
ref = locale->help_missing;
}
if (ref)
{
return g_strconcat (domain->help_uri, "/",
locale->locale_id, "/",
ref,
NULL);
}
else /* try to assemble a useful error message */
{
GError *error = NULL;
#ifdef GIMP_HELP_DEBUG
g_printerr ("help: help_id lookup and all fallbacks failed for '%s'\n",
help_id);
#endif
locale = domain_locale_lookup (domain, GIMP_HELP_DEFAULT_LOCALE);
if (! domain_locale_parse (domain, locale, &error))
{
if (error->code == G_FILE_ERROR_NOENT)
{
g_message ("%s\n\n%s",
_("The GIMP help files are not found."),
_("Please install the additional help package or use "
"the online user manual at http://docs.gimp.org/."));
}
else
{
g_message ("%s\n\n%s\n\n%s",
_("There is a problem with the GIMP help files."),
error->message,
_("Please check your installation."));
}
g_error_free (error);
help_exit ();
}
else
{
g_message (_("Help ID '%s' unknown"), help_id);
}
return NULL;
}
}
void
domain_exit (void)
{
if (domain_hash)
{
g_hash_table_destroy (domain_hash);
domain_hash = NULL;
}
}
/* private functions */
static HelpDomain *
domain_new (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root)
{
HelpDomain *domain = g_new0 (HelpDomain, 1);
domain->help_domain = g_strdup (domain_name);
domain->help_uri = g_strdup (domain_uri);
domain->help_root = g_strdup (domain_root);
if (domain_uri)
{
/* strip trailing slash */
gint len = strlen (domain_uri);
if (len &&
domain_uri[len - 1] == '/')
domain->help_uri[len - 1] = '\0';
}
return domain;
}
static void
domain_free (HelpDomain *domain)
{
g_return_if_fail (domain != NULL);
if (domain->help_locales)
g_hash_table_destroy (domain->help_locales);
g_free (domain->help_domain);
g_free (domain->help_uri);
g_free (domain->help_root);
g_free (domain);
}
static
HelpLocale *
domain_locale_new (const gchar *locale_id)
{
HelpLocale *locale = g_new0 (HelpLocale, 1);
locale->locale_id = g_strdup (locale_id);
return locale;
}
static void
domain_locale_free (HelpLocale *locale)
{
if (locale->help_id_mapping)
g_hash_table_destroy (locale->help_id_mapping);
g_free (locale->locale_id);
g_free (locale->help_missing);
}
static HelpLocale *
domain_locale_lookup (HelpDomain *domain,
const gchar *locale_id)
{
HelpLocale *locale = NULL;
if (domain->help_locales)
locale = g_hash_table_lookup (domain->help_locales, locale_id);
else
domain->help_locales =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) domain_locale_free);
if (locale)
return locale;
locale = domain_locale_new (locale_id);
g_hash_table_insert (domain->help_locales, g_strdup (locale_id), locale);
domain_locale_parse (domain, locale, NULL);
return locale;
}
static const gchar *
domain_locale_map (HelpLocale *locale,
const gchar *help_id)
{
if (! locale->help_id_mapping)
return NULL;
return g_hash_table_lookup (locale->help_id_mapping, help_id);
}
/* the domain mapping parser */
typedef enum
{
DOMAIN_START,
DOMAIN_IN_HELP,
DOMAIN_IN_ITEM,
DOMAIN_IN_MISSING,
DOMAIN_IN_UNKNOWN
} DomainParserState;
typedef struct
{
const gchar *filename;
DomainParserState state;
DomainParserState last_known_state;
gint markup_depth;
gint unknown_depth;
GString *value;
HelpDomain *domain;
HelpLocale *locale;
gchar *id_attr_name;
} DomainParser;
static gboolean domain_parser_parse (GMarkupParseContext *context,
GIOChannel *io,
GError **error);
static void domain_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error);
static void domain_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error);
static void domain_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data);
static void domain_parser_start_unknown (DomainParser *parser);
static void domain_parser_end_unknown (DomainParser *parser);
static void domain_parser_parse_namespace (DomainParser *parser,
const gchar **names,
const gchar **values);
static void domain_parser_parse_item (DomainParser *parser,
const gchar **names,
const gchar **values);
static void domain_parser_parse_missing (DomainParser *parser,
const gchar **names,
const gchar **values);
static const GMarkupParser markup_parser =
{
domain_parser_start_element,
domain_parser_end_element,
NULL, /* characters */
NULL, /* passthrough */
domain_parser_error
};
static gboolean
domain_locale_parse (HelpDomain *domain,
HelpLocale *locale,
GError **error)
{
GMarkupParseContext *context;
DomainParser *parser;
GIOChannel *io;
gchar *filename;
gboolean success;
g_return_val_if_fail (domain != NULL, FALSE);
g_return_val_if_fail (locale != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (locale->help_id_mapping)
{
g_hash_table_destroy (locale->help_id_mapping);
locale->help_id_mapping = NULL;
}
if (locale->help_missing)
{
g_free (locale->help_missing);
locale->help_missing = NULL;
}
if (! domain->help_root)
domain->help_root = filename_from_uri (domain->help_uri);
if (! domain->help_root)
{
g_set_error (error, 0, 0,
"Cannot determine location of gimp-help.xml from '%s'",
domain->help_uri);
return FALSE;
}
filename = g_build_filename (domain->help_root,
locale->locale_id,
"gimp-help.xml",
NULL);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): parsing '%s' for domain \"%s\"\n",
locale->locale_id,
filename,
domain->help_domain);
#endif
io = g_io_channel_new_file (filename, "r", error);
if (! io)
{
domain_error_set_message (error,
_("Could not open '%s' for reading: %s"),
filename);
g_free (filename);
return FALSE;
}
parser = g_new0 (DomainParser, 1);
parser->filename = filename;
parser->value = g_string_new (NULL);
parser->id_attr_name = g_strdup ("id");
parser->domain = domain;
parser->locale = locale;
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
success = domain_parser_parse (context, io, error);
g_markup_parse_context_free (context);
g_io_channel_unref (io);
g_string_free (parser->value, TRUE);
g_free (parser->id_attr_name);
g_free (parser);
if (! success)
domain_error_set_message (error, _("Parse error in '%s':\n%s"), filename);
g_free (filename);
return success;
}
static gboolean
domain_parser_parse (GMarkupParseContext *context,
GIOChannel *io,
GError **error)
{
GIOStatus status;
gsize len;
gchar buffer[4096];
while (TRUE)
{
status = g_io_channel_read_chars (io,
buffer, sizeof (buffer), &len, error);
switch (status)
{
case G_IO_STATUS_ERROR:
return FALSE;
case G_IO_STATUS_EOF:
return g_markup_parse_context_end_parse (context, error);
case G_IO_STATUS_NORMAL:
if (! g_markup_parse_context_parse (context, buffer, len, error))
return FALSE;
break;
case G_IO_STATUS_AGAIN:
break;
}
}
return TRUE;
}
static void
domain_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
DomainParser *parser = (DomainParser *) user_data;
switch (parser->state)
{
case DOMAIN_START:
if (strcmp (element_name, "gimp-help") == 0)
{
parser->state = DOMAIN_IN_HELP;
domain_parser_parse_namespace (parser,
attribute_names, attribute_values);
}
else
domain_parser_start_unknown (parser);
break;
case DOMAIN_IN_HELP:
if (strcmp (element_name, "help-item") == 0)
{
parser->state = DOMAIN_IN_ITEM;
domain_parser_parse_item (parser,
attribute_names, attribute_values);
}
else if (strcmp (element_name, "help-missing") == 0)
{
parser->state = DOMAIN_IN_MISSING;
domain_parser_parse_missing (parser,
attribute_names, attribute_values);
}
else
domain_parser_start_unknown (parser);
break;
case DOMAIN_IN_ITEM:
case DOMAIN_IN_MISSING:
case DOMAIN_IN_UNKNOWN:
domain_parser_start_unknown (parser);
break;
}
}
static void
domain_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error)
{
DomainParser *parser = (DomainParser *) user_data;
switch (parser->state)
{
case DOMAIN_START:
g_warning ("domain_parser: This shouldn't happen.");
break;
case DOMAIN_IN_HELP:
parser->state = DOMAIN_START;
break;
case DOMAIN_IN_ITEM:
case DOMAIN_IN_MISSING:
parser->state = DOMAIN_IN_HELP;
break;
case DOMAIN_IN_UNKNOWN:
domain_parser_end_unknown (parser);
break;
}
}
static void
domain_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data)
{
DomainParser *parser = (DomainParser *) user_data;
g_printerr ("help (parsing %s): %s", parser->filename, error->message);
}
static void
domain_parser_start_unknown (DomainParser *parser)
{
if (parser->unknown_depth == 0)
parser->last_known_state = parser->state;
parser->state = DOMAIN_IN_UNKNOWN;
parser->unknown_depth++;
}
static void
domain_parser_end_unknown (DomainParser *parser)
{
g_assert (parser->unknown_depth > 0 && parser->state == DOMAIN_IN_UNKNOWN);
parser->unknown_depth--;
if (parser->unknown_depth == 0)
parser->state = parser->last_known_state;
}
static void
domain_parser_parse_namespace (DomainParser *parser,
const gchar **names,
const gchar **values)
{
for (; *names && *values; names++, values++)
{
if (! strncmp (*names, "xmlns:", 6) &&
! strcmp (*values, parser->domain->help_domain))
{
g_free (parser->id_attr_name);
parser->id_attr_name = g_strdup_printf ("%s:id", *names + 6);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): id attribute name for \"%s\" is \"%s\"\n",
parser->locale->locale_id,
parser->domain->help_domain,
parser->id_attr_name);
#endif
}
}
}
static void
domain_parser_parse_item (DomainParser *parser,
const gchar **names,
const gchar **values)
{
const gchar *id = NULL;
const gchar *ref = NULL;
for (; *names && *values; names++, values++)
{
if (! strcmp (*names, parser->id_attr_name))
id = *values;
if (! strcmp (*names, "ref"))
ref = *values;
}
if (id && ref)
{
if (! parser->locale->help_id_mapping)
parser->locale->help_id_mapping = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_free);
g_hash_table_insert (parser->locale->help_id_mapping,
g_strdup (id), g_strdup (ref));
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): added mapping \"%s\" -> \"%s\"\n",
parser->locale->locale_id, id, ref);
#endif
}
}
static void
domain_parser_parse_missing (DomainParser *parser,
const gchar **names,
const gchar **values)
{
const gchar *ref = NULL;
for (; *names && *values; names++, values++)
{
if (! strcmp (*names, "ref"))
ref = *values;
}
if (ref &&
parser->locale->help_missing == NULL)
{
parser->locale->help_missing = g_strdup (ref);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): added fallback for missing help -> \"%s\"\n",
parser->locale->locale_id, ref);
#endif
}
}
static void
domain_error_set_message (GError **error,
const gchar *format,
const gchar *filename)
{
if (error && *error)
{
gchar *name = g_filename_display_name (filename);
gchar *msg = g_strdup_printf (format, name, (*error)->message);
g_free (name);
g_free ((*error)->message);
(*error)->message = msg;
}
}
static gchar *
filename_from_uri (const gchar *uri)
{
gchar *filename;
gchar *hostname;
g_return_val_if_fail (uri != NULL, NULL);
filename = g_filename_from_uri (uri, &hostname, NULL);
if (!filename)
return NULL;
if (hostname)
{
/* we have a file: URI with a hostname */
#ifdef G_OS_WIN32
/* on Win32, create a valid UNC path and use it as the filename */
gchar *tmp = g_build_filename ("//", hostname, filename, NULL);
g_free (filename);
filename = tmp;
#else
/* otherwise return NULL, caller should use URI then */
g_free (filename);
filename = NULL;
#endif
g_free (hostname);
}
return filename;
}

View File

@ -29,9 +29,7 @@
#include "libgimpbase/gimpversion.h" #include "libgimpbase/gimpversion.h"
#include "libgimpbase/gimpenv.h" #include "libgimpbase/gimpenv.h"
#include "domain.h" #include "gimphelp.h"
#include "help.h"
#include "locales.h"
static void show_version (void) G_GNUC_NORETURN; static void show_version (void) G_GNUC_NORETURN;
@ -99,7 +97,7 @@ main (gint argc,
else else
uri = g_filename_to_uri (help_root, NULL, NULL); uri = g_filename_to_uri (help_root, NULL, NULL);
domain_register (GIMP_HELP_DEFAULT_DOMAIN, uri, help_root); gimp_help_register_domain (GIMP_HELP_DEFAULT_DOMAIN, uri, help_root);
g_free (uri); g_free (uri);
uri = lookup (GIMP_HELP_DEFAULT_DOMAIN, uri = lookup (GIMP_HELP_DEFAULT_DOMAIN,
@ -118,23 +116,17 @@ main (gint argc,
return uri ? EXIT_SUCCESS : EXIT_FAILURE; return uri ? EXIT_SUCCESS : EXIT_FAILURE;
} }
void
help_exit (void)
{
/* nothing */
}
static gchar * static gchar *
lookup (const gchar *help_domain, lookup (const gchar *help_domain,
const gchar *help_locales, const gchar *help_locales,
const gchar *help_id) const gchar *help_id)
{ {
HelpDomain *domain = domain_lookup (help_domain); GimpHelpDomain *domain = gimp_help_lookup_domain (help_domain);
if (domain) if (domain)
{ {
GList *locales = locales_parse (help_locales); GList *locales = gimp_help_parse_locales (help_locales);
gchar *full_uri = domain_map (domain, locales, help_id); gchar *full_uri = gimp_help_domain_map (domain, locales, help_id, NULL);
g_list_foreach (locales, (GFunc) g_free, NULL); g_list_foreach (locales, (GFunc) g_free, NULL);
g_list_free (locales); g_list_free (locales);

View File

@ -29,10 +29,11 @@
#include <string.h> #include <string.h>
#include <glib.h> #include <glib-object.h>
#include "domain.h" #include "libgimpbase/gimpbase.h"
#include "help.h"
#include "gimphelp.h"
#ifdef DISABLE_NLS #ifdef DISABLE_NLS
#define _(String) (String) #define _(String) (String)
@ -41,49 +42,6 @@
#endif #endif
struct _HelpDomain
{
gchar *help_domain;
gchar *help_uri;
gchar *help_root;
GHashTable *help_locales;
};
typedef struct _HelpLocale HelpLocale;
struct _HelpLocale
{
gchar *locale_id;
GHashTable *help_id_mapping;
gchar *help_missing;
};
/* local function prototypes */
static HelpDomain * domain_new (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root);
static void domain_free (HelpDomain *domain);
static HelpLocale * domain_locale_new (const gchar *locale_id);
static void domain_locale_free (HelpLocale *locale);
static HelpLocale * domain_locale_lookup (HelpDomain *domain,
const gchar *locale_id);
static const gchar * domain_locale_map (HelpLocale *locale,
const gchar *help_id);
static gboolean domain_locale_parse (HelpDomain *domain,
HelpLocale *locale,
GError **error);
static void domain_error_set_message (GError **error,
const gchar *format,
const gchar *filename);
static gchar * filename_from_uri (const gchar *uri);
/* private variables */ /* private variables */
static GHashTable *domain_hash = NULL; static GHashTable *domain_hash = NULL;
@ -91,10 +49,68 @@ static GHashTable *domain_hash = NULL;
/* public functions */ /* public functions */
gboolean
gimp_help_init (gint num_domain_names,
gchar **domain_names,
gint num_domain_uris,
gchar **domain_uris)
{
const gchar *default_env_domain_uri;
gchar *default_domain_uri;
gint i;
if (num_domain_names != num_domain_uris)
{
g_printerr ("help: number of names doesn't match number of URIs.\n");
return FALSE;
}
/* set default values */
default_env_domain_uri = g_getenv (GIMP_HELP_ENV_URI);
if (default_env_domain_uri)
{
default_domain_uri = g_strdup (default_env_domain_uri);
}
else
{
gchar *help_root = g_build_filename (gimp_data_directory (),
GIMP_HELP_PREFIX,
NULL);
default_domain_uri = g_filename_to_uri (help_root, NULL, NULL);
g_free (help_root);
}
gimp_help_register_domain (GIMP_HELP_DEFAULT_DOMAIN,
default_domain_uri, NULL);
for (i = 0; i < num_domain_names; i++)
{
gimp_help_register_domain (domain_names[i], domain_uris[i], NULL);
}
g_free (default_domain_uri);
return TRUE;
}
void void
domain_register (const gchar *domain_name, gimp_help_exit (void)
const gchar *domain_uri, {
const gchar *domain_root) if (domain_hash)
{
g_hash_table_destroy (domain_hash);
domain_hash = NULL;
}
}
void
gimp_help_register_domain (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root)
{ {
g_return_if_fail (domain_name != NULL); g_return_if_fail (domain_name != NULL);
g_return_if_fail (domain_uri != NULL); g_return_if_fail (domain_uri != NULL);
@ -106,15 +122,17 @@ domain_register (const gchar *domain_name,
if (! domain_hash) if (! domain_hash)
domain_hash = g_hash_table_new_full (g_str_hash, g_str_equal, domain_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) domain_free); g_free,
(GDestroyNotify) gimp_help_domain_free);
g_hash_table_insert (domain_hash, g_hash_table_insert (domain_hash,
g_strdup (domain_name), g_strdup (domain_name),
domain_new (domain_name, domain_uri, domain_root)); gimp_help_domain_new (domain_name,
domain_uri, domain_root));
} }
HelpDomain * GimpHelpDomain *
domain_lookup (const gchar *domain_name) gimp_help_lookup_domain (const gchar *domain_name)
{ {
g_return_val_if_fail (domain_name, NULL); g_return_val_if_fail (domain_name, NULL);
@ -124,609 +142,43 @@ domain_lookup (const gchar *domain_name)
return NULL; return NULL;
} }
gchar * GList *
domain_map (HelpDomain *domain, gimp_help_parse_locales (const gchar *help_locales)
GList *help_locales,
const gchar *help_id)
{ {
HelpLocale *locale = NULL; GList *locales = NULL;
const gchar *ref = NULL;
GList *list; GList *list;
const gchar *s;
const gchar *p;
g_return_val_if_fail (domain != NULL, NULL);
g_return_val_if_fail (help_locales != NULL, NULL); g_return_val_if_fail (help_locales != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
/* first pass: look for a reference matching the help_id */ /* split the string at colons, building a list */
for (list = help_locales; list && !ref; list = list->next) s = help_locales;
for (p = strchr (s, ':'); p; p = strchr (s, ':'))
{ {
locale = domain_locale_lookup (domain, (const gchar *) list->data); gchar *new = g_strndup (s, p - s);
ref = domain_locale_map (locale, help_id);
locales = g_list_append (locales, new);
s = p + 1;
} }
/* second pass: look for a fallback */ if (*s)
for (list = help_locales; list && !ref; list = list->next) locales = g_list_append (locales, g_strdup (s));
{
locale = domain_locale_lookup (domain, (const gchar *) list->data);
ref = locale->help_missing;
}
if (ref) /* if the list doesn't contain the default domain yet, append it */
{ for (list = locales; list; list = list->next)
return g_strconcat (domain->help_uri, "/", if (strcmp ((const gchar *) list->data, GIMP_HELP_DEFAULT_LOCALE) == 0)
locale->locale_id, "/", break;
ref,
NULL); if (! list)
} locales = g_list_append (locales, g_strdup (GIMP_HELP_DEFAULT_LOCALE));
else /* try to assemble a useful error message */
{
GError *error = NULL;
#ifdef GIMP_HELP_DEBUG #ifdef GIMP_HELP_DEBUG
g_printerr ("help: help_id lookup and all fallbacks failed for '%s'\n", g_printerr ("help: locales: ");
help_id); for (list = locales; list; list = list->next)
g_printerr ("%s ", (const gchar *) list->data);
g_printerr ("\n");
#endif #endif
locale = domain_locale_lookup (domain, GIMP_HELP_DEFAULT_LOCALE); return locales;
if (! domain_locale_parse (domain, locale, &error))
{
if (error->code == G_FILE_ERROR_NOENT)
{
g_message ("%s\n\n%s",
_("The GIMP help files are not found."),
_("Please install the additional help package or use "
"the online user manual at http://docs.gimp.org/."));
}
else
{
g_message ("%s\n\n%s\n\n%s",
_("There is a problem with the GIMP help files."),
error->message,
_("Please check your installation."));
}
g_error_free (error);
help_exit ();
}
else
{
g_message (_("Help ID '%s' unknown"), help_id);
}
return NULL;
}
}
void
domain_exit (void)
{
if (domain_hash)
{
g_hash_table_destroy (domain_hash);
domain_hash = NULL;
}
}
/* private functions */
static HelpDomain *
domain_new (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root)
{
HelpDomain *domain = g_new0 (HelpDomain, 1);
domain->help_domain = g_strdup (domain_name);
domain->help_uri = g_strdup (domain_uri);
domain->help_root = g_strdup (domain_root);
if (domain_uri)
{
/* strip trailing slash */
gint len = strlen (domain_uri);
if (len &&
domain_uri[len - 1] == '/')
domain->help_uri[len - 1] = '\0';
}
return domain;
}
static void
domain_free (HelpDomain *domain)
{
g_return_if_fail (domain != NULL);
if (domain->help_locales)
g_hash_table_destroy (domain->help_locales);
g_free (domain->help_domain);
g_free (domain->help_uri);
g_free (domain->help_root);
g_free (domain);
}
static
HelpLocale *
domain_locale_new (const gchar *locale_id)
{
HelpLocale *locale = g_new0 (HelpLocale, 1);
locale->locale_id = g_strdup (locale_id);
return locale;
}
static void
domain_locale_free (HelpLocale *locale)
{
if (locale->help_id_mapping)
g_hash_table_destroy (locale->help_id_mapping);
g_free (locale->locale_id);
g_free (locale->help_missing);
}
static HelpLocale *
domain_locale_lookup (HelpDomain *domain,
const gchar *locale_id)
{
HelpLocale *locale = NULL;
if (domain->help_locales)
locale = g_hash_table_lookup (domain->help_locales, locale_id);
else
domain->help_locales =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) domain_locale_free);
if (locale)
return locale;
locale = domain_locale_new (locale_id);
g_hash_table_insert (domain->help_locales, g_strdup (locale_id), locale);
domain_locale_parse (domain, locale, NULL);
return locale;
}
static const gchar *
domain_locale_map (HelpLocale *locale,
const gchar *help_id)
{
if (! locale->help_id_mapping)
return NULL;
return g_hash_table_lookup (locale->help_id_mapping, help_id);
}
/* the domain mapping parser */
typedef enum
{
DOMAIN_START,
DOMAIN_IN_HELP,
DOMAIN_IN_ITEM,
DOMAIN_IN_MISSING,
DOMAIN_IN_UNKNOWN
} DomainParserState;
typedef struct
{
const gchar *filename;
DomainParserState state;
DomainParserState last_known_state;
gint markup_depth;
gint unknown_depth;
GString *value;
HelpDomain *domain;
HelpLocale *locale;
gchar *id_attr_name;
} DomainParser;
static gboolean domain_parser_parse (GMarkupParseContext *context,
GIOChannel *io,
GError **error);
static void domain_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error);
static void domain_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error);
static void domain_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data);
static void domain_parser_start_unknown (DomainParser *parser);
static void domain_parser_end_unknown (DomainParser *parser);
static void domain_parser_parse_namespace (DomainParser *parser,
const gchar **names,
const gchar **values);
static void domain_parser_parse_item (DomainParser *parser,
const gchar **names,
const gchar **values);
static void domain_parser_parse_missing (DomainParser *parser,
const gchar **names,
const gchar **values);
static const GMarkupParser markup_parser =
{
domain_parser_start_element,
domain_parser_end_element,
NULL, /* characters */
NULL, /* passthrough */
domain_parser_error
};
static gboolean
domain_locale_parse (HelpDomain *domain,
HelpLocale *locale,
GError **error)
{
GMarkupParseContext *context;
DomainParser *parser;
GIOChannel *io;
gchar *filename;
gboolean success;
g_return_val_if_fail (domain != NULL, FALSE);
g_return_val_if_fail (locale != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (locale->help_id_mapping)
{
g_hash_table_destroy (locale->help_id_mapping);
locale->help_id_mapping = NULL;
}
if (locale->help_missing)
{
g_free (locale->help_missing);
locale->help_missing = NULL;
}
if (! domain->help_root)
domain->help_root = filename_from_uri (domain->help_uri);
if (! domain->help_root)
{
g_set_error (error, 0, 0,
"Cannot determine location of gimp-help.xml from '%s'",
domain->help_uri);
return FALSE;
}
filename = g_build_filename (domain->help_root,
locale->locale_id,
"gimp-help.xml",
NULL);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): parsing '%s' for domain \"%s\"\n",
locale->locale_id,
filename,
domain->help_domain);
#endif
io = g_io_channel_new_file (filename, "r", error);
if (! io)
{
domain_error_set_message (error,
_("Could not open '%s' for reading: %s"),
filename);
g_free (filename);
return FALSE;
}
parser = g_new0 (DomainParser, 1);
parser->filename = filename;
parser->value = g_string_new (NULL);
parser->id_attr_name = g_strdup ("id");
parser->domain = domain;
parser->locale = locale;
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
success = domain_parser_parse (context, io, error);
g_markup_parse_context_free (context);
g_io_channel_unref (io);
g_string_free (parser->value, TRUE);
g_free (parser->id_attr_name);
g_free (parser);
if (! success)
domain_error_set_message (error, _("Parse error in '%s':\n%s"), filename);
g_free (filename);
return success;
}
static gboolean
domain_parser_parse (GMarkupParseContext *context,
GIOChannel *io,
GError **error)
{
GIOStatus status;
gsize len;
gchar buffer[4096];
while (TRUE)
{
status = g_io_channel_read_chars (io,
buffer, sizeof (buffer), &len, error);
switch (status)
{
case G_IO_STATUS_ERROR:
return FALSE;
case G_IO_STATUS_EOF:
return g_markup_parse_context_end_parse (context, error);
case G_IO_STATUS_NORMAL:
if (! g_markup_parse_context_parse (context, buffer, len, error))
return FALSE;
break;
case G_IO_STATUS_AGAIN:
break;
}
}
return TRUE;
}
static void
domain_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
DomainParser *parser = (DomainParser *) user_data;
switch (parser->state)
{
case DOMAIN_START:
if (strcmp (element_name, "gimp-help") == 0)
{
parser->state = DOMAIN_IN_HELP;
domain_parser_parse_namespace (parser,
attribute_names, attribute_values);
}
else
domain_parser_start_unknown (parser);
break;
case DOMAIN_IN_HELP:
if (strcmp (element_name, "help-item") == 0)
{
parser->state = DOMAIN_IN_ITEM;
domain_parser_parse_item (parser,
attribute_names, attribute_values);
}
else if (strcmp (element_name, "help-missing") == 0)
{
parser->state = DOMAIN_IN_MISSING;
domain_parser_parse_missing (parser,
attribute_names, attribute_values);
}
else
domain_parser_start_unknown (parser);
break;
case DOMAIN_IN_ITEM:
case DOMAIN_IN_MISSING:
case DOMAIN_IN_UNKNOWN:
domain_parser_start_unknown (parser);
break;
}
}
static void
domain_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error)
{
DomainParser *parser = (DomainParser *) user_data;
switch (parser->state)
{
case DOMAIN_START:
g_warning ("domain_parser: This shouldn't happen.");
break;
case DOMAIN_IN_HELP:
parser->state = DOMAIN_START;
break;
case DOMAIN_IN_ITEM:
case DOMAIN_IN_MISSING:
parser->state = DOMAIN_IN_HELP;
break;
case DOMAIN_IN_UNKNOWN:
domain_parser_end_unknown (parser);
break;
}
}
static void
domain_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data)
{
DomainParser *parser = (DomainParser *) user_data;
g_printerr ("help (parsing %s): %s", parser->filename, error->message);
}
static void
domain_parser_start_unknown (DomainParser *parser)
{
if (parser->unknown_depth == 0)
parser->last_known_state = parser->state;
parser->state = DOMAIN_IN_UNKNOWN;
parser->unknown_depth++;
}
static void
domain_parser_end_unknown (DomainParser *parser)
{
g_assert (parser->unknown_depth > 0 && parser->state == DOMAIN_IN_UNKNOWN);
parser->unknown_depth--;
if (parser->unknown_depth == 0)
parser->state = parser->last_known_state;
}
static void
domain_parser_parse_namespace (DomainParser *parser,
const gchar **names,
const gchar **values)
{
for (; *names && *values; names++, values++)
{
if (! strncmp (*names, "xmlns:", 6) &&
! strcmp (*values, parser->domain->help_domain))
{
g_free (parser->id_attr_name);
parser->id_attr_name = g_strdup_printf ("%s:id", *names + 6);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): id attribute name for \"%s\" is \"%s\"\n",
parser->locale->locale_id,
parser->domain->help_domain,
parser->id_attr_name);
#endif
}
}
}
static void
domain_parser_parse_item (DomainParser *parser,
const gchar **names,
const gchar **values)
{
const gchar *id = NULL;
const gchar *ref = NULL;
for (; *names && *values; names++, values++)
{
if (! strcmp (*names, parser->id_attr_name))
id = *values;
if (! strcmp (*names, "ref"))
ref = *values;
}
if (id && ref)
{
if (! parser->locale->help_id_mapping)
parser->locale->help_id_mapping = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_free);
g_hash_table_insert (parser->locale->help_id_mapping,
g_strdup (id), g_strdup (ref));
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): added mapping \"%s\" -> \"%s\"\n",
parser->locale->locale_id, id, ref);
#endif
}
}
static void
domain_parser_parse_missing (DomainParser *parser,
const gchar **names,
const gchar **values)
{
const gchar *ref = NULL;
for (; *names && *values; names++, values++)
{
if (! strcmp (*names, "ref"))
ref = *values;
}
if (ref &&
parser->locale->help_missing == NULL)
{
parser->locale->help_missing = g_strdup (ref);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): added fallback for missing help -> \"%s\"\n",
parser->locale->locale_id, ref);
#endif
}
}
static void
domain_error_set_message (GError **error,
const gchar *format,
const gchar *filename)
{
if (error && *error)
{
gchar *name = g_filename_display_name (filename);
gchar *msg = g_strdup_printf (format, name, (*error)->message);
g_free (name);
g_free ((*error)->message);
(*error)->message = msg;
}
}
static gchar *
filename_from_uri (const gchar *uri)
{
gchar *filename;
gchar *hostname;
g_return_val_if_fail (uri != NULL, NULL);
filename = g_filename_from_uri (uri, &hostname, NULL);
if (!filename)
return NULL;
if (hostname)
{
/* we have a file: URI with a hostname */
#ifdef G_OS_WIN32
/* on Win32, create a valid UNC path and use it as the filename */
gchar *tmp = g_build_filename ("//", hostname, filename, NULL);
g_free (filename);
filename = tmp;
#else
/* otherwise return NULL, caller should use URI then */
g_free (filename);
filename = NULL;
#endif
g_free (hostname);
}
return filename;
} }

59
plug-ins/help/gimphelp.h Normal file
View File

@ -0,0 +1,59 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* The GIMP Help plug-in
* Copyright (C) 1999-2004 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
* Henrik Brix Andersen <brix@gimp.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __GIMP_HELP_H__
#define __GIMP_HELP_H__
#include "gimphelptypes.h"
#include "gimphelpdomain.h"
#include "gimphelpitem.h"
#include "gimphelplocale.h"
#define GIMP_HELP_DEFAULT_DOMAIN "http://www.gimp.org/help"
#define GIMP_HELP_DEFAULT_ID "gimp-main"
#define GIMP_HELP_DEFAULT_LOCALE "en"
#define GIMP_HELP_PREFIX "help"
#define GIMP_HELP_ENV_URI "GIMP2_HELP_URI"
#define GIMP_HELP_DEBUG
gboolean gimp_help_init (gint n_domain_names,
gchar **domain_names,
gint n_domain_uris,
gchar **domain_uris);
void gimp_help_exit (void);
void gimp_help_register_domain (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root);
GimpHelpDomain * gimp_help_lookup_domain (const gchar *domain_name);
GList * gimp_help_parse_locales (const gchar *help_locales);
#endif /* ! __GIMP_HELP_H__ */

View File

@ -29,10 +29,11 @@
#include <string.h> #include <string.h>
#include <glib.h> #include <glib-object.h>
#include "domain.h" #include "libgimpbase/gimpbase.h"
#include "help.h"
#include "gimphelp.h"
#ifdef DISABLE_NLS #ifdef DISABLE_NLS
#define _(String) (String) #define _(String) (String)
@ -41,113 +42,107 @@
#endif #endif
struct _HelpDomain
{
gchar *help_domain;
gchar *help_uri;
gchar *help_root;
GHashTable *help_locales;
};
typedef struct _HelpLocale HelpLocale;
struct _HelpLocale
{
gchar *locale_id;
GHashTable *help_id_mapping;
gchar *help_missing;
};
/* local function prototypes */ /* local function prototypes */
static HelpDomain * domain_new (const gchar *domain_name, static gboolean domain_locale_parse (GimpHelpDomain *domain,
const gchar *domain_uri, GimpHelpLocale *locale,
const gchar *domain_root); GError **error);
static void domain_free (HelpDomain *domain);
static HelpLocale * domain_locale_new (const gchar *locale_id); static gchar * domain_filename_from_uri (const gchar *uri);
static void domain_locale_free (HelpLocale *locale);
static HelpLocale * domain_locale_lookup (HelpDomain *domain,
const gchar *locale_id);
static const gchar * domain_locale_map (HelpLocale *locale,
const gchar *help_id);
static gboolean domain_locale_parse (HelpDomain *domain,
HelpLocale *locale,
GError **error);
static void domain_error_set_message (GError **error,
const gchar *format,
const gchar *filename);
static gchar * filename_from_uri (const gchar *uri);
/* private variables */
static GHashTable *domain_hash = NULL;
/* public functions */ /* public functions */
void GimpHelpDomain *
domain_register (const gchar *domain_name, gimp_help_domain_new (const gchar *domain_name,
const gchar *domain_uri, const gchar *domain_uri,
const gchar *domain_root) const gchar *domain_root)
{ {
g_return_if_fail (domain_name != NULL); GimpHelpDomain *domain = g_new0 (GimpHelpDomain, 1);
g_return_if_fail (domain_uri != NULL);
#ifdef GIMP_HELP_DEBUG domain->help_domain = g_strdup (domain_name);
g_printerr ("help: registering help domain \"%s\" with base uri \"%s\"\n", domain->help_uri = g_strdup (domain_uri);
domain_name, domain_uri); domain->help_root = g_strdup (domain_root);
#endif
if (! domain_hash) if (domain_uri)
domain_hash = g_hash_table_new_full (g_str_hash, g_str_equal, {
g_free, (GDestroyNotify) domain_free); /* strip trailing slash */
if (g_str_has_suffix (domain->help_uri, "/"))
domain->help_uri[strlen (domain->help_uri) - 1] = '\0';
}
g_hash_table_insert (domain_hash, return domain;
g_strdup (domain_name),
domain_new (domain_name, domain_uri, domain_root));
} }
HelpDomain * void
domain_lookup (const gchar *domain_name) gimp_help_domain_free (GimpHelpDomain *domain)
{ {
g_return_val_if_fail (domain_name, NULL); g_return_if_fail (domain != NULL);
if (domain_hash) if (domain->help_locales)
return g_hash_table_lookup (domain_hash, domain_name); g_hash_table_destroy (domain->help_locales);
return NULL; g_free (domain->help_domain);
g_free (domain->help_uri);
g_free (domain->help_root);
g_free (domain);
}
GimpHelpLocale *
gimp_help_domain_lookup_locale (GimpHelpDomain *domain,
const gchar *locale_id)
{
GimpHelpLocale *locale = NULL;
if (domain->help_locales)
locale = g_hash_table_lookup (domain->help_locales, locale_id);
else
domain->help_locales =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) gimp_help_locale_free);
if (locale)
return locale;
locale = gimp_help_locale_new (locale_id);
g_hash_table_insert (domain->help_locales, g_strdup (locale_id), locale);
domain_locale_parse (domain, locale, NULL);
return locale;
} }
gchar * gchar *
domain_map (HelpDomain *domain, gimp_help_domain_map (GimpHelpDomain *domain,
GList *help_locales, GList *help_locales,
const gchar *help_id) const gchar *help_id,
gboolean *fatal_error)
{ {
HelpLocale *locale = NULL; GimpHelpLocale *locale = NULL;
const gchar *ref = NULL; const gchar *ref = NULL;
GList *list; GList *list;
g_return_val_if_fail (domain != NULL, NULL); g_return_val_if_fail (domain != NULL, NULL);
g_return_val_if_fail (help_locales != NULL, NULL); g_return_val_if_fail (help_locales != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL); g_return_val_if_fail (help_id != NULL, NULL);
if (fatal_error)
*fatal_error = FALSE;
/* first pass: look for a reference matching the help_id */ /* first pass: look for a reference matching the help_id */
for (list = help_locales; list && !ref; list = list->next) for (list = help_locales; list && !ref; list = list->next)
{ {
locale = domain_locale_lookup (domain, (const gchar *) list->data); locale = gimp_help_domain_lookup_locale (domain,
ref = domain_locale_map (locale, help_id); (const gchar *) list->data);
ref = gimp_help_locale_map (locale, help_id);
} }
/* second pass: look for a fallback */ /* second pass: look for a fallback */
for (list = help_locales; list && !ref; list = list->next) for (list = help_locales; list && !ref; list = list->next)
{ {
locale = domain_locale_lookup (domain, (const gchar *) list->data); locale = gimp_help_domain_lookup_locale (domain,
(const gchar *) list->data);
ref = locale->help_missing; ref = locale->help_missing;
} }
@ -167,7 +162,8 @@ domain_map (HelpDomain *domain,
help_id); help_id);
#endif #endif
locale = domain_locale_lookup (domain, GIMP_HELP_DEFAULT_LOCALE); locale = gimp_help_domain_lookup_locale (domain,
GIMP_HELP_DEFAULT_LOCALE);
if (! domain_locale_parse (domain, locale, &error)) if (! domain_locale_parse (domain, locale, &error))
{ {
@ -188,7 +184,8 @@ domain_map (HelpDomain *domain,
g_error_free (error); g_error_free (error);
help_exit (); if (fatal_error)
*fatal_error = TRUE;
} }
else else
{ {
@ -199,205 +196,23 @@ domain_map (HelpDomain *domain,
} }
} }
void
domain_exit (void)
{
if (domain_hash)
{
g_hash_table_destroy (domain_hash);
domain_hash = NULL;
}
}
/* private functions */ /* private functions */
static HelpDomain *
domain_new (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root)
{
HelpDomain *domain = g_new0 (HelpDomain, 1);
domain->help_domain = g_strdup (domain_name);
domain->help_uri = g_strdup (domain_uri);
domain->help_root = g_strdup (domain_root);
if (domain_uri)
{
/* strip trailing slash */
gint len = strlen (domain_uri);
if (len &&
domain_uri[len - 1] == '/')
domain->help_uri[len - 1] = '\0';
}
return domain;
}
static void
domain_free (HelpDomain *domain)
{
g_return_if_fail (domain != NULL);
if (domain->help_locales)
g_hash_table_destroy (domain->help_locales);
g_free (domain->help_domain);
g_free (domain->help_uri);
g_free (domain->help_root);
g_free (domain);
}
static
HelpLocale *
domain_locale_new (const gchar *locale_id)
{
HelpLocale *locale = g_new0 (HelpLocale, 1);
locale->locale_id = g_strdup (locale_id);
return locale;
}
static void
domain_locale_free (HelpLocale *locale)
{
if (locale->help_id_mapping)
g_hash_table_destroy (locale->help_id_mapping);
g_free (locale->locale_id);
g_free (locale->help_missing);
}
static HelpLocale *
domain_locale_lookup (HelpDomain *domain,
const gchar *locale_id)
{
HelpLocale *locale = NULL;
if (domain->help_locales)
locale = g_hash_table_lookup (domain->help_locales, locale_id);
else
domain->help_locales =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) domain_locale_free);
if (locale)
return locale;
locale = domain_locale_new (locale_id);
g_hash_table_insert (domain->help_locales, g_strdup (locale_id), locale);
domain_locale_parse (domain, locale, NULL);
return locale;
}
static const gchar *
domain_locale_map (HelpLocale *locale,
const gchar *help_id)
{
if (! locale->help_id_mapping)
return NULL;
return g_hash_table_lookup (locale->help_id_mapping, help_id);
}
/* the domain mapping parser */
typedef enum
{
DOMAIN_START,
DOMAIN_IN_HELP,
DOMAIN_IN_ITEM,
DOMAIN_IN_MISSING,
DOMAIN_IN_UNKNOWN
} DomainParserState;
typedef struct
{
const gchar *filename;
DomainParserState state;
DomainParserState last_known_state;
gint markup_depth;
gint unknown_depth;
GString *value;
HelpDomain *domain;
HelpLocale *locale;
gchar *id_attr_name;
} DomainParser;
static gboolean domain_parser_parse (GMarkupParseContext *context,
GIOChannel *io,
GError **error);
static void domain_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error);
static void domain_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error);
static void domain_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data);
static void domain_parser_start_unknown (DomainParser *parser);
static void domain_parser_end_unknown (DomainParser *parser);
static void domain_parser_parse_namespace (DomainParser *parser,
const gchar **names,
const gchar **values);
static void domain_parser_parse_item (DomainParser *parser,
const gchar **names,
const gchar **values);
static void domain_parser_parse_missing (DomainParser *parser,
const gchar **names,
const gchar **values);
static const GMarkupParser markup_parser =
{
domain_parser_start_element,
domain_parser_end_element,
NULL, /* characters */
NULL, /* passthrough */
domain_parser_error
};
static gboolean static gboolean
domain_locale_parse (HelpDomain *domain, domain_locale_parse (GimpHelpDomain *domain,
HelpLocale *locale, GimpHelpLocale *locale,
GError **error) GError **error)
{ {
GMarkupParseContext *context; gchar *filename;
DomainParser *parser; gboolean success;
GIOChannel *io;
gchar *filename;
gboolean success;
g_return_val_if_fail (domain != NULL, FALSE); g_return_val_if_fail (domain != NULL, FALSE);
g_return_val_if_fail (locale != NULL, FALSE); g_return_val_if_fail (locale != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (locale->help_id_mapping)
{
g_hash_table_destroy (locale->help_id_mapping);
locale->help_id_mapping = NULL;
}
if (locale->help_missing)
{
g_free (locale->help_missing);
locale->help_missing = NULL;
}
if (! domain->help_root) if (! domain->help_root)
domain->help_root = filename_from_uri (domain->help_uri); domain->help_root = domain_filename_from_uri (domain->help_uri);
if (! domain->help_root) if (! domain->help_root)
{ {
@ -412,292 +227,18 @@ domain_locale_parse (HelpDomain *domain,
"gimp-help.xml", "gimp-help.xml",
NULL); NULL);
#ifdef GIMP_HELP_DEBUG success = gimp_help_locale_parse (locale,
g_printerr ("help (%s): parsing '%s' for domain \"%s\"\n", filename,
locale->locale_id, domain->help_domain,
filename, error);
domain->help_domain);
#endif
io = g_io_channel_new_file (filename, "r", error);
if (! io)
{
domain_error_set_message (error,
_("Could not open '%s' for reading: %s"),
filename);
g_free (filename);
return FALSE;
}
parser = g_new0 (DomainParser, 1);
parser->filename = filename;
parser->value = g_string_new (NULL);
parser->id_attr_name = g_strdup ("id");
parser->domain = domain;
parser->locale = locale;
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
success = domain_parser_parse (context, io, error);
g_markup_parse_context_free (context);
g_io_channel_unref (io);
g_string_free (parser->value, TRUE);
g_free (parser->id_attr_name);
g_free (parser);
if (! success)
domain_error_set_message (error, _("Parse error in '%s':\n%s"), filename);
g_free (filename); g_free (filename);
return success; return success;
} }
static gboolean
domain_parser_parse (GMarkupParseContext *context,
GIOChannel *io,
GError **error)
{
GIOStatus status;
gsize len;
gchar buffer[4096];
while (TRUE)
{
status = g_io_channel_read_chars (io,
buffer, sizeof (buffer), &len, error);
switch (status)
{
case G_IO_STATUS_ERROR:
return FALSE;
case G_IO_STATUS_EOF:
return g_markup_parse_context_end_parse (context, error);
case G_IO_STATUS_NORMAL:
if (! g_markup_parse_context_parse (context, buffer, len, error))
return FALSE;
break;
case G_IO_STATUS_AGAIN:
break;
}
}
return TRUE;
}
static void
domain_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
DomainParser *parser = (DomainParser *) user_data;
switch (parser->state)
{
case DOMAIN_START:
if (strcmp (element_name, "gimp-help") == 0)
{
parser->state = DOMAIN_IN_HELP;
domain_parser_parse_namespace (parser,
attribute_names, attribute_values);
}
else
domain_parser_start_unknown (parser);
break;
case DOMAIN_IN_HELP:
if (strcmp (element_name, "help-item") == 0)
{
parser->state = DOMAIN_IN_ITEM;
domain_parser_parse_item (parser,
attribute_names, attribute_values);
}
else if (strcmp (element_name, "help-missing") == 0)
{
parser->state = DOMAIN_IN_MISSING;
domain_parser_parse_missing (parser,
attribute_names, attribute_values);
}
else
domain_parser_start_unknown (parser);
break;
case DOMAIN_IN_ITEM:
case DOMAIN_IN_MISSING:
case DOMAIN_IN_UNKNOWN:
domain_parser_start_unknown (parser);
break;
}
}
static void
domain_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error)
{
DomainParser *parser = (DomainParser *) user_data;
switch (parser->state)
{
case DOMAIN_START:
g_warning ("domain_parser: This shouldn't happen.");
break;
case DOMAIN_IN_HELP:
parser->state = DOMAIN_START;
break;
case DOMAIN_IN_ITEM:
case DOMAIN_IN_MISSING:
parser->state = DOMAIN_IN_HELP;
break;
case DOMAIN_IN_UNKNOWN:
domain_parser_end_unknown (parser);
break;
}
}
static void
domain_parser_error (GMarkupParseContext *context,
GError *error,
gpointer user_data)
{
DomainParser *parser = (DomainParser *) user_data;
g_printerr ("help (parsing %s): %s", parser->filename, error->message);
}
static void
domain_parser_start_unknown (DomainParser *parser)
{
if (parser->unknown_depth == 0)
parser->last_known_state = parser->state;
parser->state = DOMAIN_IN_UNKNOWN;
parser->unknown_depth++;
}
static void
domain_parser_end_unknown (DomainParser *parser)
{
g_assert (parser->unknown_depth > 0 && parser->state == DOMAIN_IN_UNKNOWN);
parser->unknown_depth--;
if (parser->unknown_depth == 0)
parser->state = parser->last_known_state;
}
static void
domain_parser_parse_namespace (DomainParser *parser,
const gchar **names,
const gchar **values)
{
for (; *names && *values; names++, values++)
{
if (! strncmp (*names, "xmlns:", 6) &&
! strcmp (*values, parser->domain->help_domain))
{
g_free (parser->id_attr_name);
parser->id_attr_name = g_strdup_printf ("%s:id", *names + 6);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): id attribute name for \"%s\" is \"%s\"\n",
parser->locale->locale_id,
parser->domain->help_domain,
parser->id_attr_name);
#endif
}
}
}
static void
domain_parser_parse_item (DomainParser *parser,
const gchar **names,
const gchar **values)
{
const gchar *id = NULL;
const gchar *ref = NULL;
for (; *names && *values; names++, values++)
{
if (! strcmp (*names, parser->id_attr_name))
id = *values;
if (! strcmp (*names, "ref"))
ref = *values;
}
if (id && ref)
{
if (! parser->locale->help_id_mapping)
parser->locale->help_id_mapping = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_free);
g_hash_table_insert (parser->locale->help_id_mapping,
g_strdup (id), g_strdup (ref));
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): added mapping \"%s\" -> \"%s\"\n",
parser->locale->locale_id, id, ref);
#endif
}
}
static void
domain_parser_parse_missing (DomainParser *parser,
const gchar **names,
const gchar **values)
{
const gchar *ref = NULL;
for (; *names && *values; names++, values++)
{
if (! strcmp (*names, "ref"))
ref = *values;
}
if (ref &&
parser->locale->help_missing == NULL)
{
parser->locale->help_missing = g_strdup (ref);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): added fallback for missing help -> \"%s\"\n",
parser->locale->locale_id, ref);
#endif
}
}
static void
domain_error_set_message (GError **error,
const gchar *format,
const gchar *filename)
{
if (error && *error)
{
gchar *name = g_filename_display_name (filename);
gchar *msg = g_strdup_printf (format, name, (*error)->message);
g_free (name);
g_free ((*error)->message);
(*error)->message = msg;
}
}
static gchar * static gchar *
filename_from_uri (const gchar *uri) domain_filename_from_uri (const gchar *uri)
{ {
gchar *filename; gchar *filename;
gchar *hostname; gchar *hostname;

View File

@ -0,0 +1,51 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* The GIMP Help plug-in
* Copyright (C) 1999-2004 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
* Henrik Brix Andersen <brix@gimp.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __DOMAIN_H__
#define __DOMAIN_H__
struct _GimpHelpDomain
{
gchar *help_domain;
gchar *help_uri;
gchar *help_root;
GHashTable *help_locales;
};
GimpHelpDomain * gimp_help_domain_new (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root);
void gimp_help_domain_free (GimpHelpDomain *domain);
GimpHelpLocale * gimp_help_domain_lookup_locale (GimpHelpDomain *domain,
const gchar *locale_id);
gchar * gimp_help_domain_map (GimpHelpDomain *domain,
GList *help_locales,
const gchar *help_id,
gboolean *fatal_error);
void gimp_help_domain_exit (void);
#endif /* ! __DOMAIN_H__ */

View File

@ -0,0 +1,68 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* The GIMP Help plug-in
* Copyright (C) 1999-2004 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
* Henrik Brix Andersen <brix@gimp.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* This code is written so that it can also be compiled standalone.
* It shouldn't depend on libgimp.
*/
#include "config.h"
#include <string.h>
#include <glib.h>
#include "gimphelptypes.h"
#include "gimphelpitem.h"
#ifdef DISABLE_NLS
#define _(String) (String)
#else
#include "libgimp/stdplugins-intl.h"
#endif
/* public functions */
GimpHelpItem *
gimp_help_item_new (const gchar *ref,
const gchar *title,
const gchar *parent)
{
GimpHelpItem *item = g_new0 (GimpHelpItem, 1);
item->ref = g_strdup (ref);
item->title = g_strdup (title);
item->parent = g_strdup (parent);
return item;
}
void
gimp_help_item_free (GimpHelpItem *item)
{
g_free (item->ref);
g_free (item->title);
g_free (item->parent);
g_free (item);
}

View File

@ -21,22 +21,25 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#ifndef __DOMAIN_H__ #ifndef __GIMP_HELP_ITEM_H__
#define __DOMAIN_H__ #define __GIMP_HELP_ITEM_H__
typedef struct _HelpDomain HelpDomain; struct _GimpHelpItem
{
gchar *ref;
gchar *title;
gchar *parent;
GList *children;
gint index;
};
void domain_register (const gchar *domain_name, GimpHelpItem * gimp_help_item_new (const gchar *ref,
const gchar *domain_uri, const gchar *title,
const gchar *domain_root); const gchar *parent);
HelpDomain * domain_lookup (const gchar *domain_name); void gimp_help_item_free (GimpHelpItem *item);
gchar * domain_map (HelpDomain *domain,
GList *help_locales,
const gchar *help_id);
void domain_exit (void);
#endif /* ! __DOMAIN_H__ */ #endif /* __GIMP_HELP_ITEM_H__ */

View File

@ -31,8 +31,7 @@
#include <glib.h> #include <glib.h>
#include "domain.h" #include "gimphelp.h"
#include "help.h"
#ifdef DISABLE_NLS #ifdef DISABLE_NLS
#define _(String) (String) #define _(String) (String)
@ -41,348 +40,129 @@
#endif #endif
struct _HelpDomain
{
gchar *help_domain;
gchar *help_uri;
gchar *help_root;
GHashTable *help_locales;
};
typedef struct _HelpLocale HelpLocale;
struct _HelpLocale
{
gchar *locale_id;
GHashTable *help_id_mapping;
gchar *help_missing;
};
/* local function prototypes */ /* local function prototypes */
static HelpDomain * domain_new (const gchar *domain_name, static void locale_set_error (GError **error,
const gchar *domain_uri, const gchar *format,
const gchar *domain_root); const gchar *filename);
static void domain_free (HelpDomain *domain);
static HelpLocale * domain_locale_new (const gchar *locale_id);
static void domain_locale_free (HelpLocale *locale);
static HelpLocale * domain_locale_lookup (HelpDomain *domain,
const gchar *locale_id);
static const gchar * domain_locale_map (HelpLocale *locale,
const gchar *help_id);
static gboolean domain_locale_parse (HelpDomain *domain,
HelpLocale *locale,
GError **error);
static void domain_error_set_message (GError **error,
const gchar *format,
const gchar *filename);
static gchar * filename_from_uri (const gchar *uri);
/* private variables */
static GHashTable *domain_hash = NULL;
/* public functions */ /* public functions */
void GimpHelpLocale *
domain_register (const gchar *domain_name, gimp_help_locale_new (const gchar *locale_id)
const gchar *domain_uri,
const gchar *domain_root)
{ {
g_return_if_fail (domain_name != NULL); GimpHelpLocale *locale = g_new0 (GimpHelpLocale, 1);
g_return_if_fail (domain_uri != NULL);
#ifdef GIMP_HELP_DEBUG
g_printerr ("help: registering help domain \"%s\" with base uri \"%s\"\n",
domain_name, domain_uri);
#endif
if (! domain_hash)
domain_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) domain_free);
g_hash_table_insert (domain_hash,
g_strdup (domain_name),
domain_new (domain_name, domain_uri, domain_root));
}
HelpDomain *
domain_lookup (const gchar *domain_name)
{
g_return_val_if_fail (domain_name, NULL);
if (domain_hash)
return g_hash_table_lookup (domain_hash, domain_name);
return NULL;
}
gchar *
domain_map (HelpDomain *domain,
GList *help_locales,
const gchar *help_id)
{
HelpLocale *locale = NULL;
const gchar *ref = NULL;
GList *list;
g_return_val_if_fail (domain != NULL, NULL);
g_return_val_if_fail (help_locales != NULL, NULL);
g_return_val_if_fail (help_id != NULL, NULL);
/* first pass: look for a reference matching the help_id */
for (list = help_locales; list && !ref; list = list->next)
{
locale = domain_locale_lookup (domain, (const gchar *) list->data);
ref = domain_locale_map (locale, help_id);
}
/* second pass: look for a fallback */
for (list = help_locales; list && !ref; list = list->next)
{
locale = domain_locale_lookup (domain, (const gchar *) list->data);
ref = locale->help_missing;
}
if (ref)
{
return g_strconcat (domain->help_uri, "/",
locale->locale_id, "/",
ref,
NULL);
}
else /* try to assemble a useful error message */
{
GError *error = NULL;
#ifdef GIMP_HELP_DEBUG
g_printerr ("help: help_id lookup and all fallbacks failed for '%s'\n",
help_id);
#endif
locale = domain_locale_lookup (domain, GIMP_HELP_DEFAULT_LOCALE);
if (! domain_locale_parse (domain, locale, &error))
{
if (error->code == G_FILE_ERROR_NOENT)
{
g_message ("%s\n\n%s",
_("The GIMP help files are not found."),
_("Please install the additional help package or use "
"the online user manual at http://docs.gimp.org/."));
}
else
{
g_message ("%s\n\n%s\n\n%s",
_("There is a problem with the GIMP help files."),
error->message,
_("Please check your installation."));
}
g_error_free (error);
help_exit ();
}
else
{
g_message (_("Help ID '%s' unknown"), help_id);
}
return NULL;
}
}
void
domain_exit (void)
{
if (domain_hash)
{
g_hash_table_destroy (domain_hash);
domain_hash = NULL;
}
}
/* private functions */
static HelpDomain *
domain_new (const gchar *domain_name,
const gchar *domain_uri,
const gchar *domain_root)
{
HelpDomain *domain = g_new0 (HelpDomain, 1);
domain->help_domain = g_strdup (domain_name);
domain->help_uri = g_strdup (domain_uri);
domain->help_root = g_strdup (domain_root);
if (domain_uri)
{
/* strip trailing slash */
gint len = strlen (domain_uri);
if (len &&
domain_uri[len - 1] == '/')
domain->help_uri[len - 1] = '\0';
}
return domain;
}
static void
domain_free (HelpDomain *domain)
{
g_return_if_fail (domain != NULL);
if (domain->help_locales)
g_hash_table_destroy (domain->help_locales);
g_free (domain->help_domain);
g_free (domain->help_uri);
g_free (domain->help_root);
g_free (domain);
}
static
HelpLocale *
domain_locale_new (const gchar *locale_id)
{
HelpLocale *locale = g_new0 (HelpLocale, 1);
locale->locale_id = g_strdup (locale_id); locale->locale_id = g_strdup (locale_id);
return locale; return locale;
} }
static void void
domain_locale_free (HelpLocale *locale) gimp_help_locale_free (GimpHelpLocale *locale)
{ {
if (locale->help_id_mapping) if (locale->help_id_mapping)
g_hash_table_destroy (locale->help_id_mapping); g_hash_table_destroy (locale->help_id_mapping);
g_free (locale->locale_id); g_free (locale->locale_id);
g_free (locale->help_missing); g_free (locale->help_missing);
g_free (locale);
} }
static HelpLocale * const gchar *
domain_locale_lookup (HelpDomain *domain, gimp_help_locale_map (GimpHelpLocale *locale,
const gchar *locale_id) const gchar *help_id)
{ {
HelpLocale *locale = NULL; if (locale->help_id_mapping)
{
GimpHelpItem *item = g_hash_table_lookup (locale->help_id_mapping,
help_id);
if (domain->help_locales) if (item)
locale = g_hash_table_lookup (domain->help_locales, locale_id); return item->ref;
else }
domain->help_locales =
g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) domain_locale_free);
if (locale) return NULL;
return locale;
locale = domain_locale_new (locale_id);
g_hash_table_insert (domain->help_locales, g_strdup (locale_id), locale);
domain_locale_parse (domain, locale, NULL);
return locale;
}
static const gchar *
domain_locale_map (HelpLocale *locale,
const gchar *help_id)
{
if (! locale->help_id_mapping)
return NULL;
return g_hash_table_lookup (locale->help_id_mapping, help_id);
} }
/* the domain mapping parser */ /* the locale mapping parser */
typedef enum typedef enum
{ {
DOMAIN_START, LOCALE_START,
DOMAIN_IN_HELP, LOCALE_IN_HELP,
DOMAIN_IN_ITEM, LOCALE_IN_ITEM,
DOMAIN_IN_MISSING, LOCALE_IN_MISSING,
DOMAIN_IN_UNKNOWN LOCALE_IN_UNKNOWN
} DomainParserState; } LocaleParserState;
typedef struct typedef struct
{ {
const gchar *filename; const gchar *filename;
DomainParserState state; LocaleParserState state;
DomainParserState last_known_state; LocaleParserState last_known_state;
gint markup_depth; gint markup_depth;
gint unknown_depth; gint unknown_depth;
GString *value; GString *value;
HelpDomain *domain; GimpHelpLocale *locale;
HelpLocale *locale; const gchar *help_domain;
gchar *id_attr_name; gchar *id_attr_name;
} DomainParser; } LocaleParser;
static gboolean domain_parser_parse (GMarkupParseContext *context, static gboolean locale_parser_parse (GMarkupParseContext *context,
GIOChannel *io, GIOChannel *io,
GError **error); GError **error);
static void domain_parser_start_element (GMarkupParseContext *context, static void locale_parser_start_element (GMarkupParseContext *context,
const gchar *element_name, const gchar *element_name,
const gchar **attribute_names, const gchar **attribute_names,
const gchar **attribute_values, const gchar **attribute_values,
gpointer user_data, gpointer user_data,
GError **error); GError **error);
static void domain_parser_end_element (GMarkupParseContext *context, static void locale_parser_end_element (GMarkupParseContext *context,
const gchar *element_name, const gchar *element_name,
gpointer user_data, gpointer user_data,
GError **error); GError **error);
static void domain_parser_error (GMarkupParseContext *context, static void locale_parser_error (GMarkupParseContext *context,
GError *error, GError *error,
gpointer user_data); gpointer user_data);
static void domain_parser_start_unknown (DomainParser *parser); static void locale_parser_start_unknown (LocaleParser *parser);
static void domain_parser_end_unknown (DomainParser *parser); static void locale_parser_end_unknown (LocaleParser *parser);
static void domain_parser_parse_namespace (DomainParser *parser, static void locale_parser_parse_namespace (LocaleParser *parser,
const gchar **names,
const gchar **values);
static void domain_parser_parse_item (DomainParser *parser,
const gchar **names, const gchar **names,
const gchar **values); const gchar **values);
static void domain_parser_parse_missing (DomainParser *parser, static void locale_parser_parse_item (LocaleParser *parser,
const gchar **names,
const gchar **values);
static void locale_parser_parse_missing (LocaleParser *parser,
const gchar **names, const gchar **names,
const gchar **values); const gchar **values);
static const GMarkupParser markup_parser = static const GMarkupParser markup_parser =
{ {
domain_parser_start_element, locale_parser_start_element,
domain_parser_end_element, locale_parser_end_element,
NULL, /* characters */ NULL, /* characters */
NULL, /* passthrough */ NULL, /* passthrough */
domain_parser_error locale_parser_error
}; };
static gboolean gboolean
domain_locale_parse (HelpDomain *domain, gimp_help_locale_parse (GimpHelpLocale *locale,
HelpLocale *locale, const gchar *filename,
GError **error) const gchar *help_domain,
GError **error)
{ {
GMarkupParseContext *context; GMarkupParseContext *context;
DomainParser *parser; LocaleParser *parser;
GIOChannel *io; GIOChannel *io;
gchar *filename;
gboolean success; gboolean success;
g_return_val_if_fail (domain != NULL, FALSE);
g_return_val_if_fail (locale != NULL, FALSE); g_return_val_if_fail (locale != NULL, FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (locale->help_id_mapping) if (locale->help_id_mapping)
@ -390,56 +170,40 @@ domain_locale_parse (HelpDomain *domain,
g_hash_table_destroy (locale->help_id_mapping); g_hash_table_destroy (locale->help_id_mapping);
locale->help_id_mapping = NULL; locale->help_id_mapping = NULL;
} }
if (locale->help_missing) if (locale->help_missing)
{ {
g_free (locale->help_missing); g_free (locale->help_missing);
locale->help_missing = NULL; locale->help_missing = NULL;
} }
if (! domain->help_root)
domain->help_root = filename_from_uri (domain->help_uri);
if (! domain->help_root)
{
g_set_error (error, 0, 0,
"Cannot determine location of gimp-help.xml from '%s'",
domain->help_uri);
return FALSE;
}
filename = g_build_filename (domain->help_root,
locale->locale_id,
"gimp-help.xml",
NULL);
#ifdef GIMP_HELP_DEBUG #ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): parsing '%s' for domain \"%s\"\n", g_printerr ("help (%s): parsing '%s' for locale \"%s\"\n",
locale->locale_id, locale->locale_id,
filename, filename,
domain->help_domain); help_domain);
#endif #endif
io = g_io_channel_new_file (filename, "r", error); io = g_io_channel_new_file (filename, "r", error);
if (! io) if (! io)
{ {
domain_error_set_message (error, locale_set_error (error,
_("Could not open '%s' for reading: %s"), _("Could not open '%s' for reading: %s"),
filename); filename);
g_free (filename);
return FALSE; return FALSE;
} }
parser = g_new0 (DomainParser, 1); parser = g_new0 (LocaleParser, 1);
parser->filename = filename; parser->filename = filename;
parser->value = g_string_new (NULL); parser->value = g_string_new (NULL);
parser->id_attr_name = g_strdup ("id");
parser->domain = domain;
parser->locale = locale; parser->locale = locale;
parser->help_domain = help_domain;
parser->id_attr_name = g_strdup ("id");
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL); context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
success = domain_parser_parse (context, io, error); success = locale_parser_parse (context, io, error);
g_markup_parse_context_free (context); g_markup_parse_context_free (context);
g_io_channel_unref (io); g_io_channel_unref (io);
@ -449,15 +213,13 @@ domain_locale_parse (HelpDomain *domain,
g_free (parser); g_free (parser);
if (! success) if (! success)
domain_error_set_message (error, _("Parse error in '%s':\n%s"), filename); locale_set_error (error, _("Parse error in '%s':\n%s"), filename);
g_free (filename);
return success; return success;
} }
static gboolean static gboolean
domain_parser_parse (GMarkupParseContext *context, locale_parser_parse (GMarkupParseContext *context,
GIOChannel *io, GIOChannel *io,
GError **error) GError **error)
{ {
@ -489,106 +251,106 @@ domain_parser_parse (GMarkupParseContext *context,
} }
static void static void
domain_parser_start_element (GMarkupParseContext *context, locale_parser_start_element (GMarkupParseContext *context,
const gchar *element_name, const gchar *element_name,
const gchar **attribute_names, const gchar **attribute_names,
const gchar **attribute_values, const gchar **attribute_values,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {
DomainParser *parser = (DomainParser *) user_data; LocaleParser *parser = (LocaleParser *) user_data;
switch (parser->state) switch (parser->state)
{ {
case DOMAIN_START: case LOCALE_START:
if (strcmp (element_name, "gimp-help") == 0) if (strcmp (element_name, "gimp-help") == 0)
{ {
parser->state = DOMAIN_IN_HELP; parser->state = LOCALE_IN_HELP;
domain_parser_parse_namespace (parser, locale_parser_parse_namespace (parser,
attribute_names, attribute_values); attribute_names, attribute_values);
} }
else else
domain_parser_start_unknown (parser); locale_parser_start_unknown (parser);
break; break;
case DOMAIN_IN_HELP: case LOCALE_IN_HELP:
if (strcmp (element_name, "help-item") == 0) if (strcmp (element_name, "help-item") == 0)
{ {
parser->state = DOMAIN_IN_ITEM; parser->state = LOCALE_IN_ITEM;
domain_parser_parse_item (parser, locale_parser_parse_item (parser,
attribute_names, attribute_values); attribute_names, attribute_values);
} }
else if (strcmp (element_name, "help-missing") == 0) else if (strcmp (element_name, "help-missing") == 0)
{ {
parser->state = DOMAIN_IN_MISSING; parser->state = LOCALE_IN_MISSING;
domain_parser_parse_missing (parser, locale_parser_parse_missing (parser,
attribute_names, attribute_values); attribute_names, attribute_values);
} }
else else
domain_parser_start_unknown (parser); locale_parser_start_unknown (parser);
break; break;
case DOMAIN_IN_ITEM: case LOCALE_IN_ITEM:
case DOMAIN_IN_MISSING: case LOCALE_IN_MISSING:
case DOMAIN_IN_UNKNOWN: case LOCALE_IN_UNKNOWN:
domain_parser_start_unknown (parser); locale_parser_start_unknown (parser);
break; break;
} }
} }
static void static void
domain_parser_end_element (GMarkupParseContext *context, locale_parser_end_element (GMarkupParseContext *context,
const gchar *element_name, const gchar *element_name,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {
DomainParser *parser = (DomainParser *) user_data; LocaleParser *parser = (LocaleParser *) user_data;
switch (parser->state) switch (parser->state)
{ {
case DOMAIN_START: case LOCALE_START:
g_warning ("domain_parser: This shouldn't happen."); g_warning ("locale_parser: This shouldn't happen.");
break; break;
case DOMAIN_IN_HELP: case LOCALE_IN_HELP:
parser->state = DOMAIN_START; parser->state = LOCALE_START;
break; break;
case DOMAIN_IN_ITEM: case LOCALE_IN_ITEM:
case DOMAIN_IN_MISSING: case LOCALE_IN_MISSING:
parser->state = DOMAIN_IN_HELP; parser->state = LOCALE_IN_HELP;
break; break;
case DOMAIN_IN_UNKNOWN: case LOCALE_IN_UNKNOWN:
domain_parser_end_unknown (parser); locale_parser_end_unknown (parser);
break; break;
} }
} }
static void static void
domain_parser_error (GMarkupParseContext *context, locale_parser_error (GMarkupParseContext *context,
GError *error, GError *error,
gpointer user_data) gpointer user_data)
{ {
DomainParser *parser = (DomainParser *) user_data; LocaleParser *parser = (LocaleParser *) user_data;
g_printerr ("help (parsing %s): %s", parser->filename, error->message); g_printerr ("help (parsing %s): %s", parser->filename, error->message);
} }
static void static void
domain_parser_start_unknown (DomainParser *parser) locale_parser_start_unknown (LocaleParser *parser)
{ {
if (parser->unknown_depth == 0) if (parser->unknown_depth == 0)
parser->last_known_state = parser->state; parser->last_known_state = parser->state;
parser->state = DOMAIN_IN_UNKNOWN; parser->state = LOCALE_IN_UNKNOWN;
parser->unknown_depth++; parser->unknown_depth++;
} }
static void static void
domain_parser_end_unknown (DomainParser *parser) locale_parser_end_unknown (LocaleParser *parser)
{ {
g_assert (parser->unknown_depth > 0 && parser->state == DOMAIN_IN_UNKNOWN); g_assert (parser->unknown_depth > 0 && parser->state == LOCALE_IN_UNKNOWN);
parser->unknown_depth--; parser->unknown_depth--;
@ -597,14 +359,14 @@ domain_parser_end_unknown (DomainParser *parser)
} }
static void static void
domain_parser_parse_namespace (DomainParser *parser, locale_parser_parse_namespace (LocaleParser *parser,
const gchar **names, const gchar **names,
const gchar **values) const gchar **values)
{ {
for (; *names && *values; names++, values++) for (; *names && *values; names++, values++)
{ {
if (! strncmp (*names, "xmlns:", 6) && if (! strncmp (*names, "xmlns:", 6) &&
! strcmp (*values, parser->domain->help_domain)) ! strcmp (*values, parser->help_domain))
{ {
g_free (parser->id_attr_name); g_free (parser->id_attr_name);
parser->id_attr_name = g_strdup_printf ("%s:id", *names + 6); parser->id_attr_name = g_strdup_printf ("%s:id", *names + 6);
@ -612,7 +374,7 @@ domain_parser_parse_namespace (DomainParser *parser,
#ifdef GIMP_HELP_DEBUG #ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): id attribute name for \"%s\" is \"%s\"\n", g_printerr ("help (%s): id attribute name for \"%s\" is \"%s\"\n",
parser->locale->locale_id, parser->locale->locale_id,
parser->domain->help_domain, parser->help_domain,
parser->id_attr_name); parser->id_attr_name);
#endif #endif
} }
@ -620,12 +382,14 @@ domain_parser_parse_namespace (DomainParser *parser,
} }
static void static void
domain_parser_parse_item (DomainParser *parser, locale_parser_parse_item (LocaleParser *parser,
const gchar **names, const gchar **names,
const gchar **values) const gchar **values)
{ {
const gchar *id = NULL; const gchar *id = NULL;
const gchar *ref = NULL; const gchar *ref = NULL;
const gchar *title = NULL;
const gchar *parent = NULL;
for (; *names && *values; names++, values++) for (; *names && *values; names++, values++)
{ {
@ -634,18 +398,26 @@ domain_parser_parse_item (DomainParser *parser,
if (! strcmp (*names, "ref")) if (! strcmp (*names, "ref"))
ref = *values; ref = *values;
if (! strcmp (*names, "title"))
title = *values;
if (! strcmp (*names, "parent"))
parent = *values;
} }
if (id && ref) if (id && ref)
{ {
if (! parser->locale->help_id_mapping) if (! parser->locale->help_id_mapping)
parser->locale->help_id_mapping = g_hash_table_new_full (g_str_hash, parser->locale->help_id_mapping =
g_str_equal, g_hash_table_new_full (g_str_hash,
g_free, g_str_equal,
g_free); g_free,
(GDestroyNotify) gimp_help_item_free);
g_hash_table_insert (parser->locale->help_id_mapping, g_hash_table_insert (parser->locale->help_id_mapping,
g_strdup (id), g_strdup (ref)); g_strdup (id),
gimp_help_item_new (ref, title, parent));
#ifdef GIMP_HELP_DEBUG #ifdef GIMP_HELP_DEBUG
g_printerr ("help (%s): added mapping \"%s\" -> \"%s\"\n", g_printerr ("help (%s): added mapping \"%s\" -> \"%s\"\n",
@ -655,7 +427,7 @@ domain_parser_parse_item (DomainParser *parser,
} }
static void static void
domain_parser_parse_missing (DomainParser *parser, locale_parser_parse_missing (LocaleParser *parser,
const gchar **names, const gchar **names,
const gchar **values) const gchar **values)
{ {
@ -680,9 +452,9 @@ domain_parser_parse_missing (DomainParser *parser,
} }
static void static void
domain_error_set_message (GError **error, locale_set_error (GError **error,
const gchar *format, const gchar *format,
const gchar *filename) const gchar *filename)
{ {
if (error && *error) if (error && *error)
{ {
@ -695,38 +467,3 @@ domain_error_set_message (GError **error,
(*error)->message = msg; (*error)->message = msg;
} }
} }
static gchar *
filename_from_uri (const gchar *uri)
{
gchar *filename;
gchar *hostname;
g_return_val_if_fail (uri != NULL, NULL);
filename = g_filename_from_uri (uri, &hostname, NULL);
if (!filename)
return NULL;
if (hostname)
{
/* we have a file: URI with a hostname */
#ifdef G_OS_WIN32
/* on Win32, create a valid UNC path and use it as the filename */
gchar *tmp = g_build_filename ("//", hostname, filename, NULL);
g_free (filename);
filename = tmp;
#else
/* otherwise return NULL, caller should use URI then */
g_free (filename);
filename = NULL;
#endif
g_free (hostname);
}
return filename;
}

View File

@ -0,0 +1,48 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* The GIMP Help plug-in
* Copyright (C) 1999-2004 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
* Henrik Brix Andersen <brix@gimp.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __GIMP_HELP_LOCALE_H__
#define __GIMP_HELP_LOCALE_H__
struct _GimpHelpLocale
{
gchar *locale_id;
GHashTable *help_id_mapping;
gchar *help_missing;
};
GimpHelpLocale * gimp_help_locale_new (const gchar *locale_id);
void gimp_help_locale_free (GimpHelpLocale *locale);
const gchar * gimp_help_locale_map (GimpHelpLocale *locale,
const gchar *help_id);
gboolean gimp_help_locale_parse (GimpHelpLocale *locale,
const gchar *filename,
const gchar *help_domain,
GError **error);
#endif /* __GIMP_HELP_LOCALE_H__ */

View File

@ -21,21 +21,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#ifndef __HELP_H__ #ifndef __GIMP_HELP_TYPES_H__
#define __HELP_H__ #define __GIMP_HELP_TYPES_H__
#define GIMP_HELP_DEFAULT_DOMAIN "http://www.gimp.org/help" typedef struct _GimpHelpDomain GimpHelpDomain;
#define GIMP_HELP_DEFAULT_ID "gimp-main" typedef struct _GimpHelpItem GimpHelpItem;
#define GIMP_HELP_DEFAULT_LOCALE "en" typedef struct _GimpHelpLocale GimpHelpLocale;
#define GIMP_HELP_PREFIX "help"
#define GIMP_HELP_ENV_URI "GIMP2_HELP_URI"
/* #define GIMP_HELP_DEBUG */
void help_exit (void); #endif /* ! __GIMP_HELP_TYPES_H__ */
#endif /* ! __HELP_H__ */

View File

@ -29,9 +29,7 @@
#include "libgimp/gimp.h" #include "libgimp/gimp.h"
#include "domain.h" #include "gimphelp.h"
#include "help.h"
#include "locales.h"
#include "libgimp/stdplugins-intl.h" #include "libgimp/stdplugins-intl.h"
@ -89,14 +87,6 @@ const GimpPlugInInfo PLUG_IN_INFO =
MAIN () MAIN ()
void
help_exit (void)
{
if (main_loop)
g_main_loop_quit (main_loop);
}
static void static void
query (void) query (void)
{ {
@ -130,54 +120,19 @@ run (const gchar *name,
gint *nreturn_vals, gint *nreturn_vals,
GimpParam **return_vals) GimpParam **return_vals)
{ {
static GimpParam values[1]; static GimpParam values[1];
GimpPDBStatusType status = GIMP_PDB_SUCCESS; GimpPDBStatusType status = GIMP_PDB_SUCCESS;
const gchar *default_env_domain_uri;
gchar *default_domain_uri;
INIT_I18N (); INIT_I18N ();
/* set default values */
default_env_domain_uri = g_getenv (GIMP_HELP_ENV_URI);
if (default_env_domain_uri)
{
default_domain_uri = g_strdup (default_env_domain_uri);
}
else
{
gchar *help_root = g_build_filename (gimp_data_directory (),
GIMP_HELP_PREFIX,
NULL);
default_domain_uri = g_filename_to_uri (help_root, NULL, NULL);
g_free (help_root);
}
/* make sure all the arguments are there */ /* make sure all the arguments are there */
if (nparams == 4) if (nparams == 4)
{ {
gint num_domain_names = param[0].data.d_int32; if (! gimp_help_init (param[0].data.d_int32,
gchar **domain_names = param[1].data.d_stringarray; param[1].data.d_stringarray,
gint num_domain_uris = param[2].data.d_int32; param[2].data.d_int32,
gchar **domain_uris = param[3].data.d_stringarray; param[3].data.d_stringarray))
if (num_domain_names == num_domain_uris)
{ {
gint i;
domain_register (GIMP_HELP_DEFAULT_DOMAIN, default_domain_uri, NULL);
for (i = 0; i < num_domain_names; i++)
{
domain_register (domain_names[i], domain_uris[i], NULL);
}
}
else
{
g_printerr ("help: number of names doesn't match number of URIs.\n");
status = GIMP_PDB_CALLING_ERROR; status = GIMP_PDB_CALLING_ERROR;
} }
} }
@ -188,8 +143,6 @@ run (const gchar *name,
status = GIMP_PDB_CALLING_ERROR; status = GIMP_PDB_CALLING_ERROR;
} }
g_free (default_domain_uri);
if (status == GIMP_PDB_SUCCESS) if (status == GIMP_PDB_SUCCESS)
{ {
main_loop = g_main_loop_new (NULL, FALSE); main_loop = g_main_loop_new (NULL, FALSE);
@ -305,17 +258,19 @@ load_help (const gchar *procedure,
static gboolean static gboolean
load_help_idle (gpointer data) load_help_idle (gpointer data)
{ {
IdleHelp *idle_help = data; IdleHelp *idle_help = data;
HelpDomain *domain; GimpHelpDomain *domain;
domain = domain_lookup (idle_help->help_domain); domain = gimp_help_lookup_domain (idle_help->help_domain);
if (domain) if (domain)
{ {
GList *locales = locales_parse (idle_help->help_locales); GList *locales = gimp_help_parse_locales (idle_help->help_locales);
gchar *full_uri; gchar *full_uri;
gboolean fatal_error;
full_uri = domain_map (domain, locales, idle_help->help_id); full_uri = gimp_help_domain_map (domain, locales, idle_help->help_id,
&fatal_error);
g_list_foreach (locales, (GFunc) g_free, NULL); g_list_foreach (locales, (GFunc) g_free, NULL);
g_list_free (locales); g_list_free (locales);
@ -339,6 +294,10 @@ load_help_idle (gpointer data)
g_free (full_uri); g_free (full_uri);
} }
else if (fatal_error)
{
g_main_loop_quit (main_loop);
}
} }
g_free (idle_help->procedure); g_free (idle_help->procedure);