libgweather r144 - in trunk: . data libgweather po po-locations



Author: vuntz
Date: Mon Apr  7 09:53:31 2008
New Revision: 144
URL: http://svn.gnome.org/viewvc/libgweather?rev=144&view=rev

Log:
Deprecate libgweather/ChangeLog.
Add svn:ignore.
And:

2008-04-07  Vincent Untz  <vuntz gnome org>

	Add gweather-xml API. Patch by Dan Winship <danw gnome org>.
	Fix bug #526015.

	* configure.in: find libxml libs/cflags
	* libgweather/gweather-xml.c: move this here from gweather/clock-applet
	and fix the XML parser to skip over unrecognized close tags as well as
	unrecognized open tags
	* libgweather/Makefile.am (libgweather_la_SOURCES): add gweather-xml.c
	(libgweatherinc_HEADERS): add gweather-xml.h


Added:
   trunk/libgweather/gweather-xml.c
   trunk/libgweather/gweather-xml.h
Modified:
   trunk/   (props changed)
   trunk/ChangeLog
   trunk/configure.in
   trunk/data/   (props changed)
   trunk/libgweather/   (props changed)
   trunk/libgweather/ChangeLog
   trunk/libgweather/Makefile.am
   trunk/po/   (props changed)
   trunk/po-locations/   (props changed)

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Mon Apr  7 09:53:31 2008
@@ -8,6 +8,7 @@
 GLIB_REQUIRED=2.13.0
 GNOME_VFS_REQUIRED=2.15.4
 GCONF_REQUIRED=2.8.0
+LIBXML_REQUIRED=2.6.0
 
 AM_MAINTAINER_MODE
 
@@ -66,6 +67,11 @@
 AC_SUBST(GTK_FLAGS)
 AC_SUBST(GTK_LIBS)
 
+dnl -- Check for libxml (required) ------------------------------------------
+PKG_CHECK_MODULES(LIBXML, libxml-2.0 >= $LIBXML_REQUIRED)
+AC_SUBST(LIBXML_FLAGS)
+AC_SUBST(LIBXML_LIBS)
+
 dnl -- check for gnome-vfs (optional) -----------------------------------------
 PKG_CHECK_MODULES(GNOME_VFS_APPLETS, 
 		  [gnome-vfs-2.0 >= $GNOME_VFS_REQUIRED])

Modified: trunk/libgweather/Makefile.am
==============================================================================
--- trunk/libgweather/Makefile.am	(original)
+++ trunk/libgweather/Makefile.am	Mon Apr  7 09:53:31 2008
@@ -3,7 +3,7 @@
 lib_LTLIBRARIES = libgweather.la
 
 libgweatherincdir = $(includedir)/libgweather
-libgweatherinc_HEADERS = weather.h gweather-gconf.h gweather-prefs.h
+libgweatherinc_HEADERS = weather.h gweather-gconf.h gweather-prefs.h gweather-xml.h
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = gweather.pc
@@ -14,20 +14,23 @@
 	weather-bom.c weather-wx.c \
 	weather-sun.c \
 	gweather-prefs.c gweather-prefs.h \
-	gweather-gconf.c gweather-gconf.h
+	gweather-gconf.c gweather-gconf.h \
+	gweather-xml.c gweather-xml.h
 
 libgweather_la_CFLAGS = \
 	-I$(top_srcdir)			\
 	-I$(srcdir)			\
 	$(WARN_CFLAGS)			\
 	$(GTK_CFLAGS)			\
+	$(LIBXML_CFLAGS)		\
 	$(GNOME_VFS_APPLETS_CFLAGS)	\
-	$(GNOME_APPLETS_CFLAGS)		\
 	-DG_LOG_DOMAIN=\"GWeather\"	\
-	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+	-DGWEATHER_XML_LOCATION=\""$(pkgdatadir)/Locations.xml"\"
 
 libgweather_la_LIBADD = \
 	$(GTK_LIBS)	\
+	$(LIBXML_LIBS)	\
 	$(GNOME_VFS_APPLETS_LIBS)
 
 libgweather_la_LDFLAGS = \
@@ -40,12 +43,10 @@
 	-I$(srcdir)			\
 	$(WARN_CFLAGS)			\
 	$(GTK_CFLAGS)			\
-	$(GNOME_APPLETS_CFLAGS)		\
 	$(GNOME_VFS_APPLETS_CFLAGS)	\
 	-DG_LOG_DOMAIN=\"GWeather\"
 
 test_metar_LDADD = \
-	$(GNOME_APPLETS_LIB) \
 	$(GNOME_VFS_APPLETS_LIB) \
 	libgweather.la
 

Added: trunk/libgweather/gweather-xml.c
==============================================================================
--- (empty file)
+++ trunk/libgweather/gweather-xml.c	Mon Apr  7 09:53:31 2008
@@ -0,0 +1,400 @@
+/* gweather-xml.c - Locations.xml parsing code
+ *
+ * Copyright (C) 2005 Ryan Lortie, 2004 Gareth Owen
+ *
+ * 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
+ */
+
+
+/* There is very little error checking in the parsing code below, it relies 
+ * heavily on the locations file being in the correct format.  If you have
+ * <name> elements within a parent element, they must come first and be
+ * grouped together.
+ * The format is as follows: 
+ * 
+ * <gweather format="1.0">
+ * <region>
+ *  <name>Name of the region</name>
+ *  <name xml:lang="xx">Translated Name</name>
+ *  <name xml:lang="zz">Another Translated Name</name>
+ *  <country>
+ *   <name>Name of the country</name>
+ *   <location>
+ *    <name>Name of the location</name>
+ *    <code>IWIN code</code>
+ *    <zone>Forecast code (North America, Australia, UK only)</zone>
+ *    <radar>Weather.com radar map code (North America only)</radar>
+ *    <coordinates>Latitude and longitude as DD-MM[-SS][H] pair</coordinates>
+ *   </location>
+ *   <state>
+ *     <location>
+ *       ....
+ *     </location>
+ *     <city>
+ *      <name>Name of city with multiple locations</city>
+ *      <zone>Forecast code</zone>
+ *      <radar>Radar Map code</radar>
+ *      <location>
+ *        ...
+ *      </location>
+ *     </city>
+ *   </state>
+ *  </country>
+ * </region>
+ * <gweather>
+ *
+ * The thing to note is that each country can either contain different locations
+ * or be split into "states" which in turn contain a list of locations.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <locale.h>
+#include <gtk/gtk.h>
+#include <libxml/xmlreader.h>
+
+#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include "gweather-xml.h"
+
+static gint
+gweather_xml_location_sort_func( GtkTreeModel *model, GtkTreeIter *a,
+                                 GtkTreeIter *b, gpointer user_data )
+{
+    gint res;
+    gchar *name_a, *name_b;
+    gchar *fold_a, *fold_b;
+        
+    gtk_tree_model_get (model, a, GWEATHER_XML_COL_LOC, &name_a, -1);
+    gtk_tree_model_get (model, b, GWEATHER_XML_COL_LOC, &name_b, -1);
+        
+    fold_a = g_utf8_casefold(name_a, -1);
+    fold_b = g_utf8_casefold(name_b, -1);
+        
+    res = g_utf8_collate(fold_a, fold_b);
+    
+    g_free(name_a);
+    g_free(name_b);
+    g_free(fold_a);
+    g_free(fold_b);
+    
+    return res;
+}
+ 
+static char*
+gweather_xml_get_value( xmlTextReaderPtr xml )
+{
+  char* value;
+
+  /* check for null node */
+  if ( xmlTextReaderIsEmptyElement( xml ) )
+    return NULL;
+    
+  /* the next "node" is the text node containing the value we want to get */
+  if( xmlTextReaderRead( xml ) != 1 )
+    return NULL;
+
+  value = (char *) xmlTextReaderValue( xml );
+
+  /* move on to the end of this node */
+  while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_END_ELEMENT )
+    if( xmlTextReaderRead( xml ) != 1 )
+    {
+      xmlFree( value );
+      return NULL;
+    }
+
+  /* consume the end element too */
+  if( xmlTextReaderRead( xml ) != 1 )
+  {
+    xmlFree( value );
+    return NULL;
+  }
+    
+  return value;
+}
+
+static char *
+gweather_xml_parse_name( xmlTextReaderPtr xml )
+{
+  const char * const *locales;
+  const char *this_language;
+  int best_match = INT_MAX;
+  char *lang, *tagname;
+  gboolean keep_going;
+  char *name = NULL;
+  int i;
+
+  locales = g_get_language_names();
+
+  do
+  {
+    /* First let's get the language */
+    lang = (char *) xmlTextReaderXmlLang( xml );
+
+    if( lang == NULL )
+      this_language = "C";
+    else
+      this_language = lang;
+
+    /* the next "node" is text node containing the actual name */
+    if( xmlTextReaderRead( xml ) != 1 )
+    {
+      xmlFree( lang );
+      return NULL;
+    }
+
+    for( i = 0; locales[i] && i < best_match; i++ )
+      if( !strcmp( locales[i], this_language ) )
+      {
+        /* if we've already encounted a less accurate
+           translation, then free it */
+        xmlFree( name );
+
+        name = (char *) xmlTextReaderValue( xml );
+        best_match = i;
+
+        break;
+      }
+
+    xmlFree( lang );
+
+    while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT )
+      if( xmlTextReaderRead( xml ) != 1 )
+      {
+        xmlFree( name );
+        return NULL;
+      }
+
+    /* if the next tag is another <name> then keep going */
+    tagname = (char *) xmlTextReaderName( xml );
+    keep_going = !strcmp( tagname, "name" );
+    xmlFree( tagname );
+
+  } while( keep_going );
+
+  return name;
+}
+
+static gboolean
+gweather_xml_parse_node (xmlTextReaderPtr xml,
+			 GtkTreeStore *store, GtkTreeIter *parent,
+                         const char *dflt_radar, const char *dflt_zone,
+			 const char *cityname)
+{
+  char *name, *code, *zone, *radar, *coordinates;
+  char **city, *nocity = NULL;
+  GtkTreeIter iter, *self;
+  gboolean is_location;
+  char *tagname;
+  gboolean ret = FALSE;
+  int tagtype;
+
+  if( (tagname = (char *) xmlTextReaderName( xml )) == NULL )
+    return FALSE;
+
+  if( !strcmp( tagname, "city" ) )
+    city = &name;
+  else
+    city = &nocity;
+
+  is_location = !strcmp( tagname, "location" );
+
+  /* if we're processing the top-level, then don't create a new iter */
+  if( !strcmp( tagname, "gweather" ) )
+    self = NULL;
+  else
+  {
+    self = &iter;
+    /* insert this node into the tree */
+    gtk_tree_store_append( store, self, parent );
+  }
+
+  xmlFree( tagname );
+
+  coordinates = NULL;
+  radar = NULL;
+  zone = NULL;
+  code = NULL;
+  name = NULL;
+
+  /* absorb the start tag */
+  if( xmlTextReaderRead( xml ) != 1 )
+    goto error_out;
+
+  /* start parsing the actual contents of the node */
+  while( (tagtype = xmlTextReaderNodeType( xml )) !=
+         XML_READER_TYPE_END_ELEMENT )
+  {
+
+    /* skip non-element types */
+    if( tagtype != XML_READER_TYPE_ELEMENT )
+    {
+      if( xmlTextReaderRead( xml ) != 1 )
+        goto error_out;
+
+      continue;
+    }
+    
+    tagname = (char *) xmlTextReaderName( xml );
+
+    if( !strcmp( tagname, "region" ) || !strcmp( tagname, "country" ) ||
+        !strcmp( tagname, "state" ) || !strcmp( tagname, "city" ) ||
+        !strcmp( tagname, "location" ) )
+    {
+      /* recursively handle sub-sections */
+      if( !gweather_xml_parse_node( xml, store, self, radar, zone, *city ) )
+        goto error_out;
+    }
+    else if ( !strcmp( tagname, "name" ) )
+    {
+      xmlFree( name );
+      if( (name = gweather_xml_parse_name( xml )) == NULL )
+        goto error_out;
+    }
+    else if ( !strcmp( tagname, "code" ) )
+    {
+      xmlFree( code );
+      if( (code = gweather_xml_get_value( xml )) == NULL )
+        goto error_out;
+    }
+    else if ( !strcmp( tagname, "zone" ) )
+    {
+      xmlFree( zone );
+      if( (zone = gweather_xml_get_value( xml )) == NULL )
+        goto error_out;
+    }
+    else if ( !strcmp( tagname, "radar" ) )
+    {
+      xmlFree( radar );
+      if( (radar = gweather_xml_get_value( xml )) == NULL )
+        goto error_out;
+    }
+    else if ( !strcmp( tagname, "coordinates" ) )
+    {
+      xmlFree( coordinates );
+      if( (coordinates = gweather_xml_get_value( xml )) == NULL )
+        goto error_out;
+    }
+    else /* some strange tag */
+    {
+      /* skip past it */
+      char *junk;
+      junk = gweather_xml_get_value( xml );
+      if( junk )
+	xmlFree( junk );
+    }
+
+    xmlFree( tagname );
+  }
+
+  if( self )
+    gtk_tree_store_set( store, self, GWEATHER_XML_COL_LOC, name, -1 );
+
+  /* absorb the end tag.  in the case of processing a <gweather> then 'self'
+     is NULL.  In this case, we let this fail since we might be at EOF */
+  if( xmlTextReaderRead( xml ) != 1 && self )
+    goto error_out;
+
+  /* if this is an actual location, setup the WeatherLocation for it */
+  if( is_location )
+  {
+    WeatherLocation *new_loc;
+
+    if( cityname == NULL )
+      cityname = name;
+
+    if( radar != NULL )
+      dflt_radar = radar;
+
+    if( zone != NULL )
+      dflt_zone = zone;
+
+    new_loc =  weather_location_new( cityname, code, dflt_zone,
+                                     dflt_radar, coordinates);
+
+    gtk_tree_store_set( store, &iter, GWEATHER_XML_COL_POINTER, new_loc, -1 );
+  }
+
+  ret = TRUE;
+
+error_out:
+  xmlFree( name );
+  xmlFree( code );
+  xmlFree( zone );
+  xmlFree( radar );
+  xmlFree( coordinates );
+
+  return ret;
+}
+
+GtkTreeModel *
+gweather_xml_load_locations( void )
+{
+  char *tagname, *format;
+  GtkTreeSortable *sortable;
+  GtkTreeStore *store = NULL;
+  xmlTextReaderPtr xml;
+  int keep_going;
+
+  /* Open the xml file containing the different locations */
+  xml = xmlNewTextReaderFilename (GWEATHER_XML_LOCATION);
+  if( xml == NULL )
+    return NULL;
+
+  /* fast forward to the first element */
+  do
+  {
+    /* if we encounter a problem here, exit right away */
+    if( xmlTextReaderRead( xml ) != 1 )
+      goto error_out;
+  } while( xmlTextReaderNodeType( xml ) != XML_READER_TYPE_ELEMENT );
+
+  /* check the name and format */
+  tagname = (char *) xmlTextReaderName( xml );
+  keep_going = tagname && !strcmp( tagname, "gweather" );
+  xmlFree( tagname );
+
+  if( !keep_going )
+    goto error_out;
+
+  format = (char *) xmlTextReaderGetAttribute( xml, (xmlChar *) "format" );
+  keep_going = format && !strcmp( format, "1.0" );
+  xmlFree( format );
+
+  if( !keep_going )
+    goto error_out;
+
+  store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+
+  if (!gweather_xml_parse_node( xml, store, NULL, NULL, NULL, NULL ))
+  {
+    g_object_unref( store );
+    store = NULL;
+    goto error_out;
+  }
+
+  /* Sort the tree */
+  sortable = GTK_TREE_SORTABLE( store );
+  gtk_tree_sortable_set_default_sort_func( sortable,
+                                           &gweather_xml_location_sort_func,
+                                           NULL, NULL);
+  gtk_tree_sortable_set_sort_column_id( sortable, 
+					GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+                                        GTK_SORT_ASCENDING );
+error_out:
+  xmlFreeTextReader( xml );
+
+  return (GtkTreeModel *)store;
+}

Added: trunk/libgweather/gweather-xml.h
==============================================================================
--- (empty file)
+++ trunk/libgweather/gweather-xml.h	Mon Apr  7 09:53:31 2008
@@ -0,0 +1,35 @@
+/* gweather-xml.h 
+ *
+ * Copyright (C) 2004 Gareth Owen
+ *
+ * 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 __GWEATHER_XML_H__
+#define __GWEATHER_XML_H__
+
+#include <gtk/gtk.h>
+#include <libgweather/weather.h>
+
+enum
+{
+    GWEATHER_XML_COL_LOC = 0,
+    GWEATHER_XML_COL_POINTER,
+    GWEATHER_XML_NUM_COLUMNS
+}; 
+
+GtkTreeModel *gweather_xml_load_locations( void );
+
+#endif /* __GWEATHER_XML_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]