/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* parser.c - Locations.xml parser
*
* Copyright 2008, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
#include "weather-priv.h"
#include "parser.h"
#include
#include
#include
/**
* mateweather_parser_get_value:
* @parser: a #MateWeatherParser
*
* Gets the text of the element whose start tag @parser is pointing to.
* Leaves @parser pointing at the next node after the element's end tag.
*
* Return value: the text of the current node, as a libxml-allocated
* string, or %NULL if the node is empty.
**/
char *
mateweather_parser_get_value (MateWeatherParser *parser)
{
char *value;
/* check for null node */
if (xmlTextReaderIsEmptyElement (parser->xml))
return NULL;
/* the next "node" is the text node containing the value we want to get */
if (xmlTextReaderRead (parser->xml) != 1)
return NULL;
value = (char *) xmlTextReaderValue (parser->xml);
/* move on to the end of this node */
while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
if (xmlTextReaderRead (parser->xml) != 1) {
xmlFree (value);
return NULL;
}
}
/* consume the end element too */
if (xmlTextReaderRead (parser->xml) != 1) {
xmlFree (value);
return NULL;
}
return value;
}
/**
* mateweather_parser_get_localized_value:
* @parser: a #MateWeatherParser
*
* Looks at the name of the element @parser is currently pointing to, and
* returns the content of either that node, or a following node with
* the same name but an "xml:lang" attribute naming one of the locale
* languages. Leaves @parser pointing to the next node after the last
* consecutive element with the same name as the original element.
*
* Return value: the localized (or unlocalized) text, as a
* libxml-allocated string, or %NULL if the node is empty.
**/
char *
mateweather_parser_get_localized_value (MateWeatherParser *parser)
{
const char *this_language;
int best_match = INT_MAX;
const char *lang, *tagname, *next_tagname;
gboolean keep_going;
char *name = NULL;
int i;
tagname = (const char *) xmlTextReaderConstName (parser->xml);
do {
/* First let's get the language */
lang = (const char *) xmlTextReaderConstXmlLang (parser->xml);
if (lang == NULL)
this_language = "C";
else
this_language = lang;
/* the next "node" is text node containing the actual name */
if (xmlTextReaderRead (parser->xml) != 1) {
if (name)
xmlFree (name);
return NULL;
}
for (i = 0; parser->locales[i] && i < best_match; i++) {
if (!strcmp (parser->locales[i], this_language)) {
/* if we've already encounted a less accurate
translation, then free it */
g_free (name);
name = (char *) xmlTextReaderValue (parser->xml);
best_match = i;
break;
}
}
/* Skip to close tag */
while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT) {
if (xmlTextReaderRead (parser->xml) != 1) {
xmlFree (name);
return NULL;
}
}
/* Skip junk */
do {
if (xmlTextReaderRead (parser->xml) != 1) {
xmlFree (name);
return NULL;
}
} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT &&
xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_END_ELEMENT);
/* if the next tag has the same name then keep going */
next_tagname = (const char *) xmlTextReaderConstName (parser->xml);
keep_going = !strcmp (next_tagname, tagname);
} while (keep_going);
return name;
}
MateWeatherParser *
mateweather_parser_new (gboolean use_regions)
{
MateWeatherParser *parser;
int zlib_support;
int i, keep_going;
char *filename;
char *tagname, *format;
time_t now;
struct tm tm;
parser = g_slice_new0 (MateWeatherParser);
parser->use_regions = use_regions;
parser->locales = g_get_language_names ();
zlib_support = xmlHasFeature (XML_WITH_ZLIB);
/* First try to load a locale-specific XML. It's much faster. */
filename = NULL;
for (i = 0; parser->locales[i] != NULL; i++) {
filename = g_strdup_printf ("%s/Locations.%s.xml",
MATEWEATHER_XML_LOCATION_DIR,
parser->locales[i]);
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
break;
g_free (filename);
filename = NULL;
if (!zlib_support)
continue;
filename = g_strdup_printf ("%s/Locations.%s.xml.gz",
MATEWEATHER_XML_LOCATION_DIR,
parser->locales[i]);
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
break;
g_free (filename);
filename = NULL;
}
/* Fall back on the file containing either all translations, or only
* the english names (depending on the configure flags).
*/
if (!filename)
filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml", NULL);
if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR) && zlib_support) {
g_free (filename);
filename = g_build_filename (MATEWEATHER_XML_LOCATION_DIR, "Locations.xml.gz", NULL);
}
/* Open the xml file containing the different locations */
parser->xml = xmlNewTextReaderFilename (filename);
g_free (filename);
if (parser->xml == NULL)
goto error_out;
/* fast forward to the first element */
do {
/* if we encounter a problem here, exit right away */
if (xmlTextReaderRead (parser->xml) != 1)
goto error_out;
} while (xmlTextReaderNodeType (parser->xml) != XML_READER_TYPE_ELEMENT);
/* check the name and format */
tagname = (char *) xmlTextReaderName (parser->xml);
keep_going = tagname && !strcmp (tagname, "mateweather");
xmlFree (tagname);
if (!keep_going)
goto error_out;
format = (char *) xmlTextReaderGetAttribute (parser->xml, (xmlChar *) "format");
keep_going = format && !strcmp (format, "1.0");
xmlFree (format);
if (!keep_going)
goto error_out;
/* Get timestamps for the start and end of this year */
now = time (NULL);
tm = *gmtime (&now);
tm.tm_mon = 0;
tm.tm_mday = 1;
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
parser->year_start = mktime (&tm);
tm.tm_year++;
parser->year_end = mktime (&tm);
return parser;
error_out:
mateweather_parser_free (parser);
return NULL;
}
void
mateweather_parser_free (MateWeatherParser *parser)
{
if (parser->xml)
xmlFreeTextReader (parser->xml);
g_slice_free (MateWeatherParser, parser);
}