app/gui/Makefile.am new files. A simple XML parser for the gimp-tips.xml
2002-02-25 Sven Neumann <sven@gimp.org> * app/gui/Makefile.am * app/gui/tips-parser.[ch]: new files. A simple XML parser for the gimp-tips.xml file. * app/gui/tips-dialog.c: Removed old gimp_tips.txt parsing code and switched to use gimp-tips.xml with the new parser. This needs some more work ...
This commit is contained in:
committed by
Sven Neumann
parent
0492a0309f
commit
d7127846be
398
app/dialogs/tips-parser.c
Normal file
398
app/dialogs/tips-parser.c
Normal file
@ -0,0 +1,398 @@
|
||||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* tips-parser.c -- Parse the gimp-tips.xml file.
|
||||
* Copyright (C) 2002 Sven Neumann <sven@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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "tips-parser.h"
|
||||
|
||||
#include "libgimp/gimpintl.h"
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TIPS_START,
|
||||
TIPS_IN_TIPS,
|
||||
TIPS_IN_TIP,
|
||||
TIPS_IN_WELCOME,
|
||||
TIPS_IN_THETIP,
|
||||
TIPS_UNKNOWN
|
||||
} TipsParserState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TIPS_LANG_NONE,
|
||||
TIPS_LANG_MATCH,
|
||||
TIPS_LANG_MISMATCH,
|
||||
} TipsParserLangState;
|
||||
|
||||
typedef struct _TipsParser TipsParser;
|
||||
struct _TipsParser
|
||||
{
|
||||
TipsParserState state;
|
||||
TipsParserState last_known_state;
|
||||
const gchar *lang;
|
||||
TipsParserLangState lang_state;
|
||||
gint unknown_depth;
|
||||
GString *value;
|
||||
|
||||
GimpTip *current_tip;
|
||||
GList *tips;
|
||||
};
|
||||
|
||||
|
||||
static void tips_parser_start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static void tips_parser_end_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static void tips_parser_characters (GMarkupParseContext *context,
|
||||
const gchar *text,
|
||||
gsize text_len,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static void tips_parser_error (GMarkupParseContext *context,
|
||||
GError *error,
|
||||
gpointer user_data);
|
||||
|
||||
static void tips_parser_start_unknown (TipsParser *parser);
|
||||
static void tips_parser_end_unknown (TipsParser *parser);
|
||||
static void tips_parser_parse_lang (TipsParser *parser,
|
||||
const gchar **names,
|
||||
const gchar **values);
|
||||
static void tips_parser_set_by_lang (TipsParser *parser,
|
||||
gchar **dest);
|
||||
|
||||
|
||||
static const GMarkupParser markup_parser =
|
||||
{
|
||||
tips_parser_start_element,
|
||||
tips_parser_end_element,
|
||||
tips_parser_characters,
|
||||
NULL, /* passthrough */
|
||||
tips_parser_error
|
||||
};
|
||||
|
||||
|
||||
GimpTip *
|
||||
gimp_tip_new (const gchar *welcome,
|
||||
const gchar *thetip)
|
||||
{
|
||||
GimpTip *tip = g_new (GimpTip, 1);
|
||||
|
||||
tip->welcome = welcome ? g_strdup (welcome) : NULL;
|
||||
tip->thetip = thetip ? g_strdup (thetip) : NULL;
|
||||
|
||||
return tip;
|
||||
}
|
||||
|
||||
void
|
||||
gimp_tip_free (GimpTip *tip)
|
||||
{
|
||||
if (!tip)
|
||||
return;
|
||||
|
||||
g_free (tip->welcome);
|
||||
g_free (tip->thetip);
|
||||
g_free (tip);
|
||||
}
|
||||
|
||||
GList *
|
||||
gimp_tips_from_file (const gchar *filename,
|
||||
const gchar *language,
|
||||
GError **error)
|
||||
{
|
||||
GMarkupParseContext *context;
|
||||
TipsParser *parser;
|
||||
FILE *fp;
|
||||
gsize bytes;
|
||||
gchar buf[4096];
|
||||
GList *tips = NULL;
|
||||
GError *parse_error = NULL;
|
||||
|
||||
fp = fopen (filename, "r");
|
||||
if (!fp)
|
||||
{
|
||||
g_set_error (error,
|
||||
0, /* error domain */
|
||||
0, /* error code */
|
||||
_("Your GIMP tips file appears to be missing!\n"
|
||||
"There should be a file called gimp-tips.xml in "
|
||||
"the tips subfolder of the GIMP data folder.\n"
|
||||
"Please check your installation."));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parser = g_new0 (TipsParser, 1);
|
||||
parser->lang = language;
|
||||
parser->value = g_string_new (NULL);
|
||||
|
||||
context = g_markup_parse_context_new (&markup_parser, 0, parser, NULL);
|
||||
|
||||
while ((bytes = fread (buf, sizeof (gchar), sizeof (buf), fp)) > 0 &&
|
||||
g_markup_parse_context_parse (context, buf, bytes, &parse_error))
|
||||
;
|
||||
|
||||
/* FIXME */
|
||||
if (parse_error)
|
||||
g_clear_error (&parse_error);
|
||||
|
||||
g_markup_parse_context_end_parse (context, &parse_error);
|
||||
|
||||
/* FIXME */
|
||||
if (parse_error)
|
||||
g_clear_error (&parse_error);
|
||||
|
||||
fclose (fp);
|
||||
g_markup_parse_context_free (context);
|
||||
|
||||
if (parser->state != TIPS_START)
|
||||
{
|
||||
g_set_error (error,
|
||||
0, /* error domain */
|
||||
0, /* error code */
|
||||
_("Your GIMP tips file could not be parsed correctly!\n"
|
||||
"Please check your installation."));
|
||||
}
|
||||
|
||||
tips = g_list_reverse (parser->tips);
|
||||
|
||||
gimp_tip_free (parser->current_tip);
|
||||
g_string_free (parser->value, TRUE);
|
||||
g_free (parser);
|
||||
|
||||
return tips;
|
||||
}
|
||||
|
||||
void
|
||||
gimp_tips_free (GList *tips)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
for (list = tips; list; list = list->next)
|
||||
gimp_tip_free (list->data);
|
||||
|
||||
g_list_free (tips);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
tips_parser_start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
TipsParser *parser = (TipsParser *) user_data;
|
||||
|
||||
switch (parser->state)
|
||||
{
|
||||
case TIPS_START:
|
||||
if (strcmp (element_name, "gimp-tips") == 0)
|
||||
parser->state = TIPS_IN_TIPS;
|
||||
else
|
||||
tips_parser_start_unknown (parser);
|
||||
break;
|
||||
|
||||
case TIPS_IN_TIPS:
|
||||
if (strcmp (element_name, "tip") == 0)
|
||||
{
|
||||
parser->state = TIPS_IN_TIP;
|
||||
parser->current_tip = g_new0 (GimpTip, 1);
|
||||
}
|
||||
else
|
||||
tips_parser_start_unknown (parser);
|
||||
break;
|
||||
|
||||
case TIPS_IN_TIP:
|
||||
if (strcmp (element_name, "welcome") == 0)
|
||||
{
|
||||
parser->state = TIPS_IN_WELCOME;
|
||||
tips_parser_parse_lang (parser, attribute_names, attribute_values);
|
||||
}
|
||||
else if (strcmp (element_name, "thetip") == 0)
|
||||
{
|
||||
parser->state = TIPS_IN_THETIP;
|
||||
tips_parser_parse_lang (parser, attribute_names, attribute_values);
|
||||
}
|
||||
else
|
||||
tips_parser_start_unknown (parser);
|
||||
break;
|
||||
|
||||
case TIPS_IN_WELCOME:
|
||||
case TIPS_IN_THETIP:
|
||||
case TIPS_UNKNOWN:
|
||||
tips_parser_start_unknown (parser);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tips_parser_end_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
TipsParser *parser = (TipsParser *) user_data;
|
||||
|
||||
switch (parser->state)
|
||||
{
|
||||
case TIPS_START:
|
||||
g_warning ("tips_parser: This shouldn't happen.\n");
|
||||
break;
|
||||
|
||||
case TIPS_IN_TIPS:
|
||||
parser->state = TIPS_START;
|
||||
break;
|
||||
|
||||
case TIPS_IN_TIP:
|
||||
parser->state = TIPS_IN_TIPS;
|
||||
parser->tips = g_list_prepend (parser->tips, parser->current_tip);
|
||||
parser->current_tip = NULL;
|
||||
break;
|
||||
|
||||
case TIPS_IN_WELCOME:
|
||||
tips_parser_set_by_lang (parser, &parser->current_tip->welcome);
|
||||
parser->state = TIPS_IN_TIP;
|
||||
break;
|
||||
|
||||
case TIPS_IN_THETIP:
|
||||
tips_parser_set_by_lang (parser, &parser->current_tip->thetip);
|
||||
parser->state = TIPS_IN_TIP;
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case TIPS_UNKNOWN:
|
||||
tips_parser_end_unknown (parser);
|
||||
}
|
||||
|
||||
g_string_assign (parser->value, "");
|
||||
}
|
||||
|
||||
static void
|
||||
tips_parser_characters (GMarkupParseContext *context,
|
||||
const gchar *text,
|
||||
gsize text_len,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
TipsParser *parser = (TipsParser *) user_data;
|
||||
|
||||
switch (parser->state)
|
||||
{
|
||||
case TIPS_IN_WELCOME:
|
||||
case TIPS_IN_THETIP:
|
||||
if (parser->lang_state != TIPS_LANG_MISMATCH)
|
||||
g_string_append (parser->value, text);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tips_parser_error (GMarkupParseContext *context,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_warning (error->message);
|
||||
}
|
||||
|
||||
static void
|
||||
tips_parser_start_unknown (TipsParser *parser)
|
||||
{
|
||||
if (parser->unknown_depth == 0)
|
||||
parser->last_known_state = parser->state;
|
||||
|
||||
parser->state = TIPS_UNKNOWN;
|
||||
parser->unknown_depth++;
|
||||
}
|
||||
|
||||
static void
|
||||
tips_parser_end_unknown (TipsParser *parser)
|
||||
{
|
||||
g_assert (parser->unknown_depth > 0 && parser->state == TIPS_UNKNOWN);
|
||||
|
||||
parser->unknown_depth--;
|
||||
|
||||
if (parser->unknown_depth == 0)
|
||||
parser->state = parser->last_known_state;
|
||||
}
|
||||
|
||||
static void
|
||||
tips_parser_parse_lang (TipsParser *parser,
|
||||
const gchar **names,
|
||||
const gchar **values)
|
||||
{
|
||||
parser->lang_state = TIPS_LANG_NONE;
|
||||
|
||||
while (*names && *values)
|
||||
{
|
||||
if (strcmp (*names, "xml:lang") == 0 && **values)
|
||||
{
|
||||
parser->lang_state = ((parser->lang &&
|
||||
strcmp (*values, parser->lang) == 0) ?
|
||||
TIPS_LANG_MATCH : TIPS_LANG_MISMATCH);
|
||||
}
|
||||
|
||||
names++;
|
||||
values++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tips_parser_set_by_lang (TipsParser *parser,
|
||||
gchar **dest)
|
||||
{
|
||||
switch (parser->lang_state)
|
||||
{
|
||||
case TIPS_LANG_NONE:
|
||||
if (!parser->lang)
|
||||
{
|
||||
g_free (*dest);
|
||||
*dest = g_strdup (parser->value->str);
|
||||
}
|
||||
else if (*dest == NULL)
|
||||
{
|
||||
*dest = g_strdup (parser->value->str);
|
||||
}
|
||||
break;
|
||||
|
||||
case TIPS_LANG_MATCH:
|
||||
g_free (*dest);
|
||||
*dest = g_strdup (parser->value->str);
|
||||
break;
|
||||
|
||||
case TIPS_LANG_MISMATCH:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user