aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Williams <peterw@ximian.com>2001-06-27 06:32:38 +0800
committerPeter Williams <peterw@src.gnome.org>2001-06-27 06:32:38 +0800
commit7f184616bdff730ee67d4f6dde5b982251be16a9 (patch)
tree96e71332178cae3977b43c4a8901fa995f325eef
parente13e11965b4d62751bf6d50f5fc65c645e6f1e2b (diff)
downloadgsoc2013-evolution-7f184616bdff730ee67d4f6dde5b982251be16a9.tar.gz
gsoc2013-evolution-7f184616bdff730ee67d4f6dde5b982251be16a9.tar.zst
gsoc2013-evolution-7f184616bdff730ee67d4f6dde5b982251be16a9.zip
libwombat:
2001-06-25 Peter Williams <peterw@ximian.com> * Makefile.am (libwombat_static_la_SOURCES): Create a static libwombat for the conduits. calendar: 2001-06-25 Peter Williams <peterw@ximian.com> * conduits/calendar/Makefile.am (INCLUDES): Fixes for srcdir != builddir. Link to the static libwombat. * conduits/todo/Makefile.am (INCLUDES): Here too. addressbook: 2001-06-25 Peter Williams <peterw@ximian.com> * conduit/Makefile.am (INCLUDES): Fix for srcdir != builddir. svn path=/trunk/; revision=10511
-rw-r--r--addressbook/ChangeLog4
-rw-r--r--addressbook/conduit/Makefile.am1
-rw-r--r--calendar/ChangeLog7
-rw-r--r--calendar/conduits/calendar/Makefile.am2
-rw-r--r--libwombat/ChangeLog5
-rw-r--r--libwombat/Makefile.am7
6 files changed, 26 insertions, 0 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog
index e98d406b16..09c75a89e0 100644
--- a/addressbook/ChangeLog
+++ b/addressbook/ChangeLog
@@ -1,3 +1,7 @@
+2001-06-25 Peter Williams <peterw@ximian.com>
+
+ * conduit/Makefile.am (INCLUDES): Fix for srcdir != builddir.
+
2001-06-25 Chris Toshok <toshok@ximian.com>
* gui/contact-list-editor/contact-list-editor.glade: change layout
diff --git a/addressbook/conduit/Makefile.am b/addressbook/conduit/Makefile.am
index ab5ea0ec50..d95d858fd8 100644
--- a/addressbook/conduit/Makefile.am
+++ b/addressbook/conduit/Makefile.am
@@ -2,6 +2,7 @@ INCLUDES = \
-I$(top_srcdir) \
-I$(top_srcdir)/addressbook \
-I$(top_srcdir)/addressbook/backend \
+ -I$(top_srcdir)/e-util \
-I$(top_builddir)/e-util \
$(BONOBO_GNOME_CFLAGS) \
$(PISOCK_CFLAGS) \
diff --git a/calendar/ChangeLog b/calendar/ChangeLog
index 95340dc1b4..1c1e0a1ecd 100644
--- a/calendar/ChangeLog
+++ b/calendar/ChangeLog
@@ -1,3 +1,10 @@
+2001-06-25 Peter Williams <peterw@ximian.com>
+
+ * conduits/calendar/Makefile.am (INCLUDES): Fixes for
+ srcdir != builddir. Link to the static libwombat.
+
+ * conduits/todo/Makefile.am (INCLUDES): Here too.
+
2001-06-24 Federico Mena Quintero <federico@ximian.com>
* gui/alarm-notify/notify-main.c (main): Initialize libglade.
diff --git a/calendar/conduits/calendar/Makefile.am b/calendar/conduits/calendar/Makefile.am
index 8d8b81a9ee..bfe253c6c4 100644
--- a/calendar/conduits/calendar/Makefile.am
+++ b/calendar/conduits/calendar/Makefile.am
@@ -3,6 +3,7 @@ INCLUDES = \
-I$(top_srcdir)/calendar \
-I$(top_srcdir)/libical/src/libical \
-I$(top_builddir)/libical/src/libical \
+ -I$(top_srcdir)/e-util \
-I$(top_builddir)/e-util \
$(BONOBO_GNOME_CFLAGS) \
$(PISOCK_CFLAGS) \
@@ -23,6 +24,7 @@ libecalendar_conduit_la_LIBADD = \
$(top_builddir)/calendar/cal-util/libcal-util-static.la \
$(top_builddir)/libversit/libversit.la \
$(top_builddir)/libical/src/libical/libical-static.la \
+ $(top_builddir)/libwombat/libwombat-static.la \
$(top_builddir)/e-util/libeconduit-static.la \
$(BONOBO_GNOME_LIBS) \
$(PISOCK_LIBS) \
diff --git a/libwombat/ChangeLog b/libwombat/ChangeLog
index e57a63dc8e..ee061f99e0 100644
--- a/libwombat/ChangeLog
+++ b/libwombat/ChangeLog
@@ -1,3 +1,8 @@
+2001-06-25 <peterw@ximian.com>
+
+ * Makefile.am (libwombat_static_la_SOURCES): Create a static
+ libwombat for the conduits.
+
2001-06-23 Jason Leach <jleach@ximian.com>
* Makefile.am: builddir != srcdir fixes.
diff --git a/libwombat/Makefile.am b/libwombat/Makefile.am
index 7219569145..9fa5bd9c70 100644
--- a/libwombat/Makefile.am
+++ b/libwombat/Makefile.am
@@ -28,3 +28,10 @@ libwombat_la_SOURCES = \
$(IDL_GENERATED) \
wombat-client.c \
$(wombatinclude_HEADERS)
+
+# Static lib for pilot conduits
+
+noinst_LTLIBRARIES = libwombat-static.la
+
+libwombat_static_la_SOURCES = $(libwombat_la_SOURCES)
+libwombat_static_la_LDFLAGS = --all-static
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
/*
 * metar.c: Metar decoding routines.
 *
 * Originally written by Papadimitriou Spiros <spapadim+@cs.cmu.ed>
 */

#include <config.h>
#include <glib.h>

#include <unistd.h>
#include <stdlib.h>
#include <regex.h>
#include <math.h>

#include <libgnome/gnome-i18n.h>

#include <string.h>

#include "e-summary.h"
#include "weather.h"

#include "metar.h"

static regex_t metar_re[RE_NUM];

/* Unit conversions and names */

#define TEMP_F_TO_C(f)  (((f) - 32.0) * 0.555556)
#define TEMP_C_TO_F(c)  (((c) * 1.8) + 32.0)
#define TEMP_UNIT_STR(units)  (((units) == UNITS_IMPERIAL) ? _(" F") : _(" C"))

#define WINDSPEED_KNOTS_TO_KPH(knots)  ((knots) * 1.851965)
#define WINDSPEED_KPH_TO_KNOTS(kph)    ((kph) * 0.539967)
#define WINDSPEED_UNIT_STR(units) (((units) == UNITS_IMPERIAL) ? _("knots") : _("kph"))

#define PRESSURE_INCH_TO_MM(inch)   ((inch) * 25.4)
#define PRESSURE_MM_TO_INCH(mm)     ((mm) * 0.03937)
#define PRESSURE_MBAR_TO_INCH(mbar) ((mbar) * 0.02963742)
#define PRESSURE_UNIT_STR(units) (((units) == UNITS_IMPERIAL) ? _("inHg") : _("mmHg"))
#define VISIBILITY_SM_TO_KM(sm)  ((sm) * 1.609344)
#define VISIBILITY_KM_TO_SM(km)  ((km) * 0.621371)
#define VISIBILITY_UNIT_STR(units) (((units) == UNITS_IMPERIAL) ? _("miles") : _("kilometers"))

static const char *sky_str[] = {
    N_("Clear sky"),
    N_("Broken clouds"),
    N_("Scattered clouds"),
    N_("Few clouds"),
    N_("Overcast")
};

const char *
weather_sky_string (Weather *w)
{
    if (w->sky < 0 ||
        w->sky >= (sizeof (sky_str) / sizeof (char *))) {
        return _("Invalid");
    }
    
    return _(sky_str[(int)w->sky]);
}

static const char *wind_direction_str[] = {
    N_("Variable"),
    N_("North"), N_("North - NorthEast"), N_("Northeast"), N_("East - NorthEast"),
    N_("East"), N_("East - Southeast"), N_("Southeast"), N_("South - Southeast"),
    N_("South"), N_("South - Southwest"), N_("Southwest"), N_("West - Southwest"),
    N_("West"), N_("West - Northwest"), N_("Northwest"), N_("North - Northwest")};

const char *
weather_wind_direction_string (Weather *w)
{
    if (w->wind < 0 ||
        w->wind >= (sizeof (wind_direction_str) / sizeof (char *))) {
        return _("Invalid");
    }

    return _(wind_direction_str[(int)w->wind]);
}

/*
 * Even though tedious, I switched to a 2D array for weather condition
 * strings, in order to facilitate internationalization, esp. for languages
 * with genders.
 *
 * I tried to come up with logical names for most phenomena, but I'm no
 * meteorologist, so there will undoubtedly be some stupid mistakes.
 * However, combinations that did not seem plausible (eg. I cannot imagine
 * what a "light tornado" may be like ;-) were filled in with "??".  If this
 * ever comes up in the weather conditions field, let me know...
 */

/*
 * Note, magic numbers, when you change the size here, make sure to change
 * the below function so that new values are recognized
 */
static const gchar *conditions_str[24][13] = {
/* NONE              
   VICINITY 
   LIGHT 
   MODERATE  
   HEAVY   
   SHALLOW   
   PATCHES     
   PARTIAL  
   THUNDERSTORM  
   BLOWING  
   SHOWERS 
   DRIFTING 
   FREEZING              
*/
/* NONE */ {
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",                         
},
/* DRIZZLE */ {
    N_("Drizzle"),
    N_("Drizzle in the vicinity"), 
    N_("Light drizzle"),
    N_("Moderate drizzle"), 
    N_("Heavy drizzle"),
    N_("Shallow drizzle"),
    N_("Patches of drizzle"),
    N_("Partial drizzle"), 
    N_("Thunderstorm"),
    N_("Windy drizzle"), 
        N_("Showers"),
    N_("Drifting drizzle"), 
    N_("Freezing drizzle")    
},
/* RAIN */ {
    N_("Rain"),
    N_("Rain in the vicinity"),
    N_("Light rain"),
    N_("Moderate rain"),
    N_("Heavy rain"),
    N_("Shallow rain"),
    N_("Patches of rain"),
    N_("Partial rainfall"),
    N_("Thunderstorm"),
    N_("Blowing rainfall"),
    N_("Rain showers"),
    N_("Drifting rain"),
    N_("Freezing rain")   
},
/* SNOW */ {
    N_("Snow"),
    N_("Snow in the vicinity"),
    N_("Light snow"),
    N_("Moderate snow"), 
    N_("Heavy snow"), 
    N_("Shallow snow"), 
    N_("Patches of snow"),  
        N_("Partial snowfall"), 
    N_("Snowstorm"),
    N_("Blowing snowfall"), 
    N_("Snow showers"), 
    N_("Drifting snow"), 
    N_("Freezing snow")
},
/* SNOW_GRAINS */ {
    N_("Snow grains"), 
    N_("Snow grains in the vicinity"), 
    N_("Light snow grains"),  
    N_("Moderate snow grains"),
    N_("Heavy snow grains"), 
    N_("Shallow snow grains"),
    N_("Patches of snow grains"),
    N_("Partial snow grains"),  
    N_("Snowstorm"),  
    N_("Blowing snow grains"), 
    N_("Snow grain showers"), 
    N_("Drifting snow grains"),
    N_("Freezing snow grains") 
},
/* ICE_CRYSTALS */ {
    N_("Ice crystals"),
    N_("Ice crystals in the vicinity"),
    N_("Few ice crystals"), 
    N_("Moderate ice crystals"), 
    N_("Heavy ice crystals"), 
    "??", 
    N_("Patches of ice crystals"),
    N_("Partial ice crystals"),
    N_("Ice crystal storm"),  
    N_("Blowing ice crystals"), 
    N_("Showers of ice crystals"),
    N_("Drifting ice crystals"),
    N_("Freezing ice crystals")
},
/* ICE_PELLETS */ {
    N_("Ice pellets"),
    N_("Ice pellets in the vicinity"),
    N_("Few ice pellets"),  
    N_("Moderate ice pellets"),
    N_("Heavy ice pellets"),
    N_("Shallow ice pellets"), 
    N_("Patches of ice pellets"),
    N_("Partial ice pellets"), 
    N_("Ice pellet storm"),  
    N_("Blowing ice pellets"), 
    N_("Showers of ice pellets"),  
    N_("Drifting ice pellets"), 
    N_("Freezing ice pellets")
},
/* HAIL */ {
    N_("Hail"),  
    N_("Hail in the vicinity"), 
        N_("Light hail"),
    N_("Moderate hail"),
    N_("Heavy hail"),  
        N_("Shallow hail"),
    N_("Patches of hail"),   
    N_("Partial hail"),  
        N_("Hailstorm"),  
    N_("Blowing hail"),  
        N_("Hail showers"),   
    N_("Drifting hail"),
    N_("Freezing hail")   
},
/* SMALL_HAIL */ {
    N_("Small hail"), 
    N_("Small hail in the vicinity"),
    N_("Light hail"),    
    N_("Moderate small hail"), 
    N_("Heavy small hail"), 
    N_("Shallow small hail"), 
    N_("Patches of small hail"),   
    N_("Partial small hail"),  
    N_("Small hailstorm"),   
    N_("Blowing small hail"), 
    N_("Showers of small hail"),   
    N_("Drifting small hail"),
    N_("Freezing small hail") 
},
/* PRECIPITATION */ {
    N_("Unknown precipitation"),
    N_("Precipitation in the vicinity"),
    N_("Light precipitation"),
    N_("Moderate precipitation"),
    N_("Heavy precipitation"),
    N_("Shallow precipitation"),
    N_("Patches of precipitation"),
    N_("Partial precipitation"),
    N_("Unknown thunderstorm"), 
    N_("Blowing precipitation"),
    N_("Showers, type unknown"),  
    N_("Drifting precipitation"),
    N_("Freezing precipitation")
},
/* MIST */ {
    N_("Mist"),  
    N_("Mist in the vicinity"),  
    N_("Light mist"),  
        N_("Moderate mist"),
    N_("Thick mist"),  
        N_("Shallow mist"), 
    N_("Patches of mist"),   
    N_("Partial mist"),  
        "??",   
    N_("Mist with wind"),   
    "??", 
    N_("Drifting mist"), 
    N_("Freezing mist")  
},
/* FOG */ {
    N_("Fog"), 
    N_("Fog in the vicinity"),  
        N_("Light fog"),  
    N_("Moderate fog"), 
    N_("Thick fog"), 
    N_("Shallow fog"),  
    N_("Patches of fog"),  
    N_("Partial fog"),  
    "??", 
    N_("Fog with wind"),  
    "??",   
    N_("Drifting fog"),  
    N_("Freezing fog")  
},
/* SMOKE */ {
    N_("Smoke"),  
    N_("Smoke in the vicinity"),
        N_("Thin smoke"),   
    N_("Moderate smoke"),
    N_("Thick smoke"), 
        N_("Shallow smoke"),
    N_("Patches of smoke"), 
        N_("Partial smoke"), 
        N_("Thunderous smoke"), 
    N_("Smoke with wind"),
    "??",   
    N_("Drifting smoke"),  
    "??"    
},
/* VOLCANIC_ASH */ {
    N_("Volcanic ash"),  
        N_("Volcanic ash in the vicinity"),
    "??",  
    N_("Moderate volcanic ash"), 
    N_("Thick volcanic ash"),
    N_("Shallow volcanic ash"),
    N_("Patches of volcanic ash"),
    N_("Partial volcanic ash"), 
    N_("Thunderous volcanic ash"),
    N_("Blowing volcanic ash"),
    N_("Showers of volcanic ash"),
    N_("Drifting volcanic ash"), 
    N_("Freezing volcanic ash")
},
/* SAND */ {
    N_("Sand"), 
    N_("Sand in the vicinity"),
    N_("Light sand"),
    N_("Moderate sand"),
    N_("Heavy sand"),  
        "??",  
    N_("Patches of sand"),   
    N_("Partial sand"),  
        "??",  
    N_("Blowing sand"),   
    "",      
    N_("Drifting sand"),  
        "??" 
},
/* HAZE */ {
    N_("Haze"), 
    N_("Haze in the vicinity"), 
        N_("Light haze"),   
    N_("Moderate haze"), 
    N_("Thick haze"),  
        N_("Shallow haze"), 
    N_("Patches of haze"),  
        N_("Partial haze"),  
        "??",     
    N_("Haze with wind"),  
    "??",   
    N_("Drifting haze"),  
        N_("Freezing haze")
},
/* SPRAY */ {
    N_("Spray"),
    N_("Spray in the vicinity"),
    N_("Light spray"),  
    N_("Moderate spray"),  
    N_("Heavy spray"), 
    N_("Shallow spray"), 
    N_("Patches of spray"),   
    N_("Partial spray"),   
    "??",    
    N_("Blowing spray"),   
    "??",    
    N_("Drifting spray"),  
    N_("Freezing spray")  
},
/* DUST */ {
    N_("Dust"),  
    N_("Dust in the vicinity"),  
    N_("Light dust"),      
    N_("Moderate dust"),   
    N_("Heavy dust"),  
        "??",   
    N_("Patches of dust"),   
    N_("Partial dust"),   
    "??",   
    N_("Blowing dust"),   
    "??",   
    N_("Drifting dust"),  
        "??"     
},
/* SQUALL */ {
    N_("Squall"), 
    N_("Squall in the vicinity"), 
    N_("Light squall"), 
    N_("Moderate squall"), 
    N_("Heavy squall"), 
    "??",  
    "??",  
    N_("Partial squall"),  
    N_("Thunderous squall"), 
    N_("Blowing squall"),  
    "??",   
    N_("Drifting squall"),  
    N_("Freezing squall")  
},
/* SANDSTORM */ {
    N_("Sandstorm"),  
    N_("Sandstorm in the vicinity"), 
    N_("Light standstorm"), 
    N_("Moderate sandstorm"),  
    N_("Heavy sandstorm"), 
    N_("Shallow sandstorm"), 
    "??",    
    N_("Partial sandstorm"),  
    N_("Thunderous sandstorm"),  
    N_("Blowing sandstorm"), 
    "??",   
    N_("Drifting sandstorm"),   
    N_("Freezing sandstorm")   
},
/* DUSTSTORM */ {
    N_("Duststorm"), 
    N_("Duststorm in the vicinity"), 
    N_("Light duststorm"),  
    N_("Moderate duststorm"),  
    N_("Heavy duststorm"),
    N_("Shallow duststorm"),  
    "??",    
    N_("Partial duststorm"),  
    N_("Thunderous duststorm"), 
    N_("Blowing duststorm"),   
    "??",   
    N_("Drifting duststorm"), 
    N_("Freezing duststorm")  
},
/* FUNNEL_CLOUD */ {
    N_("Funnel cloud"),  
        N_("Funnel cloud in the vicinity"),
    N_("Light funnel cloud"), 
    N_("Moderate funnel cloud"), 
    N_("Thick funnel cloud"), 
    N_("Shallow funnel cloud"), 
    N_("Patches of funnel clouds"),
    N_("Partial funnel clouds"),
    "??",  
    N_("Funnel cloud w/ wind"), 
    "??",   
    N_("Drifting funnel cloud"),  
    "??"  
},
/* TORNADO */ {
    N_("Tornado"),   
    N_("Tornado in the vicinity"), 
    "??",  
    N_("Moderate tornado"), 
    N_("Raging tornado"), 
    "??",  
    "??",   
    N_("Partial tornado"),  
    N_("Thunderous tornado"),  
    N_("Tornado"),
    "??",  
    N_("Drifting tornado"),  
    N_("Freezing tornado") 
},
/* DUST_WHIRLS */ {
    N_("Dust whirls"),   
        N_("Dust whirls in the vicinity"), 
    N_("Light dust whirls"),
    N_("Moderate dust whirls"),  
    N_("Heavy dust whirls"),
    N_("Shallow dust whirls"), 
    N_("Patches of dust whirls"),
    N_("Partial dust whirls"), 
    "??",  
    N_("Blowing dust whirls"),  
    "??",    
    N_("Drifting dust whirls"),  
    "??"   
}
};

const char *
weather_conditions_string (Weather *w)
{
    if (!w->cond.significant) {
        return " ";
    } else {
        if (w->cond.phenomenon >= 0 &&
        w->cond.phenomenon < 24 &&
        w->cond.qualifier >= 0 &&
        w->cond.qualifier < 13) {
            return _(conditions_str[(int)w->cond.phenomenon][(int)w->cond.qualifier]);
        } else {
            return _("Invalid");
        }
    }
}

char *
weather_temp_string (Weather *w)
{
    char *temp;
    ESummaryWeatherUnits units;

    if (w->summary->preferences == NULL) {
        units = UNITS_METRIC;
    } else {
        units = w->summary->preferences->units;
    }

    temp = g_strdup_printf ("%.1f%s", w->temp, TEMP_UNIT_STR (units));
    return temp;
}

void
metar_init_re (void)
{
    static gboolean initialized = FALSE;
    if (initialized)
        return;
    initialized = TRUE;
    
    regcomp(&metar_re[TIME_RE], TIME_RE_STR, REG_EXTENDED);
    regcomp(&metar_re[WIND_RE], WIND_RE_STR, REG_EXTENDED);
    regcomp(&metar_re[VIS_RE], VIS_RE_STR, REG_EXTENDED);
    regcomp(&metar_re[CLOUD_RE], CLOUD_RE_STR, REG_EXTENDED);
    regcomp(&metar_re[TEMP_RE], TEMP_RE_STR, REG_EXTENDED);
    regcomp(&metar_re[PRES_RE], PRES_RE_STR, REG_EXTENDED);
    regcomp(&metar_re[COND_RE], COND_RE_STR, REG_EXTENDED);
}

static inline gint 
days_in_month (gint month, 
           gint year)
{
    if (month == 1)
        return ((year % 4) == 0) ? 29 : 28;
    else if (((month <= 6) && (month % 2 == 0)) || ((month >=7) && (month % 2 != 0)))
        return 31;
    else
        return 30;
}

/* FIX - there *must* be a simpler, less stupid way to do this!... */
static time_t 
make_time (gint date, 
       gint hour, 
       gint min)
{
    struct tm *tm;
    struct tm tms;
    time_t now;
    gint loc_mday, loc_hour, gm_mday, gm_hour;
    gint hour_diff;  /* local time = UTC - hour_diff */
    gint is_dst;
    
    now = time(NULL);
    
    tm = gmtime(&now);
    gm_mday = tm->tm_mday;
    gm_hour = tm->tm_hour;
    memcpy(&tms, tm, sizeof(struct tm));
    
    tm = localtime(&now);
    loc_mday = tm->tm_mday;
    loc_hour = tm->tm_hour;
    is_dst = tm->tm_isdst;
    
    /* Estimate timezone */
    if (gm_mday == loc_mday)
        hour_diff = gm_hour - loc_hour;
    else
        if ((gm_mday == loc_mday + 1) || ((gm_mday == 1) && (loc_mday >= 27)))
            hour_diff = gm_hour + (24 - loc_hour);
        else
            hour_diff = -((24 - gm_hour) + loc_hour);
    
    /* Make time */
    tms.tm_min  = min;
    tms.tm_sec  = 0;
    tms.tm_hour = hour - hour_diff;
    tms.tm_mday = date;
    tms.tm_isdst = is_dst;
    if (tms.tm_hour < 0) {
        tms.tm_hour += 24;
        --tms.tm_mday;
        if (tms.tm_mday < 1) {
            --tms.tm_mon;
            if (tms.tm_mon < 0) {
                tms.tm_mon = 11;
                --tms.tm_year;
            }
            tms.tm_mday = days_in_month(tms.tm_mon, tms.tm_year + 1900);
        }
    } else if (tms.tm_hour > 23) {
        tms.tm_hour -= 24;
        ++tms.tm_mday;
        if (tms.tm_mday > days_in_month(tms.tm_mon, tms.tm_year + 1900)) {
            ++tms.tm_mon;
            if (tms.tm_mon > 11) {
                tms.tm_mon = 0;
                ++tms.tm_year;
            }
            tms.tm_mday = 1;
        }
    }
    
    return mktime(&tms);
}

gboolean
metar_tok_time (char *token,
        Weather *w)
{
    char sday[3], shr[3], smin[3];
    int day, hour, min;

    if (regexec (&metar_re[TIME_RE], token, 0, NULL, 0) == REG_NOMATCH) {
        return FALSE;
    }

    strncpy(sday, token, 2);
    sday[2] = 0;
    day = atoi (sday);

    strncpy (shr, token + 2, 2);
    shr[2] = 0;
    hour = atoi (shr);

    strncpy (smin, token + 4, 2);
    smin[2] = 0;
    min = atoi (smin);

    w->update = make_time (day, hour, min);
    
    return TRUE;
}

#define CONST_DIGITS "0123456789"

gboolean 
metar_tok_wind (gchar *tokp, 
        Weather *w)
{
    char sdir[4], sspd[4], sgust[4];
    int dir, spd, gust = -1;
    char *gustp;
    
    if (regexec(&metar_re[WIND_RE], tokp, 0, NULL, 0) == REG_NOMATCH)
        return FALSE;
    
    strncpy(sdir, tokp, 3);
    sdir[3] = 0;
    dir = (!strcmp(sdir, "VRB")) ? -1 : atoi(sdir);
    
    memset(sspd, 0, sizeof(sspd));
    strncpy(sspd, tokp+3, strspn(tokp+3, CONST_DIGITS));
    spd = atoi(sspd);
    
    gustp = strchr(tokp, 'G');
    if (gustp) {
        memset(sgust, 0, sizeof(sgust));
        strncpy(sgust, gustp+1, strspn(gustp+1, CONST_DIGITS));
        gust = atoi(sgust);
    }
    
    if ((349 <= dir) && (dir <= 11))
        w->wind = WIND_N;
    else if ((12 <= dir) && (dir <= 33))
        w->wind = WIND_NNE;
    else if ((34 <= dir) && (dir <= 56))
        w->wind = WIND_NE;
    else if ((57 <= dir) && (dir <= 78))
        w->wind = WIND_ENE;
    else if ((79 <= dir) && (dir <= 101))
        w->wind = WIND_E;
    else if ((102 <= dir) && (dir <= 123))
        w->wind = WIND_ESE;
    else if ((124 <= dir) && (dir <= 146))
        w->wind = WIND_SE;
    else if ((147 <= dir) && (dir <= 168))
        w->wind = WIND_SSE;
    else if ((169 <= dir) && (dir <= 191))
        w->wind = WIND_S;
    else if ((192 <= dir) && (dir <= 213))
        w->wind = WIND_SSW;
    else if ((214 <= dir) && (dir <= 236))
        w->wind = WIND_SW;
    else if ((247 <= dir) && (dir <= 258))
        w->wind = WIND_WSW;
    else if ((259 <= dir) && (dir <= 281))
        w->wind = WIND_W;
    else if ((282 <= dir) && (dir <= 303))
        w->wind = WIND_WNW;
    else if ((304 <= dir) && (dir <= 326))
        w->wind = WIND_NW;
    else if ((327 <= dir) && (dir <= 348))
        w->wind = WIND_NNW;
    
    w->windspeed = (ESummaryWeatherWindSpeed)spd;
    
    return TRUE;
}

gboolean 
metar_tok_vis (gchar *tokp, 
           Weather *w)
{
    char *pfrac, *pend;
    char sval[4];
    int val;
    
    if (regexec(&metar_re[VIS_RE], tokp, 0, NULL, 0) == REG_NOMATCH)
        return FALSE;
    
    pfrac = strchr(tokp, '/');
    pend = strstr(tokp, "SM");
    memset(sval, 0, sizeof(sval));
    
    if (pfrac) {
        strncpy(sval, pfrac + 1, pend - pfrac - 1);
        val = atoi(sval);
        w->visibility = (*tokp == 'M') ? 0.001 : (1.0 / ((ESummaryWeatherVisibility)val));
    } else {
        strncpy(sval, tokp, pend - tokp);
        val = atoi(sval);
        w->visibility = (ESummaryWeatherVisibility)val;
    }
    
    return TRUE;
}

gboolean 
metar_tok_cloud (gchar *tokp, 
         Weather *w)
{
    char stype[4], salt[4];
    int alt = -1;
    
    if (regexec(&metar_re[CLOUD_RE], tokp, 0, NULL, 0) == REG_NOMATCH)
        return FALSE;
    
    strncpy(stype, tokp, 3);
    stype[3] = 0;
    if (strlen(tokp) == 6) {
        strncpy(salt, tokp+3, 3);
        salt[3] = 0;
        alt = atoi(salt);  /* Altitude - currently unused */
    }
    
    if (!strcmp(stype, "CLR")) {
        w->sky = SKY_CLEAR;
    } else if (!strcmp(stype, "BKN")) {
        w->sky = SKY_BROKEN;
    } else if (!strcmp(stype, "SCT")) {
        w->sky = SKY_SCATTERED;
    } else if (!strcmp(stype, "FEW")) {
        w->sky = SKY_FEW;
    } else if (!strcmp(stype, "OVC")) {
        w->sky = SKY_OVERCAST;
    }
    
    return TRUE;
}

gboolean 
metar_tok_pres (gchar *tokp, 
        Weather *w)
{
    if (regexec(&metar_re[PRES_RE], tokp, 0, NULL, 0) == REG_NOMATCH)
        return FALSE;
    
    if (*tokp == 'A') {
        char sintg[3], sfract[3];
        int intg, fract;
        
        strncpy(sintg, tokp+1, 2);
        sintg[2] = 0;
        intg = atoi(sintg);
        
        strncpy(sfract, tokp+3, 2);
        sfract[2] = 0;
        fract = atoi(sfract);
        
        w->pressure = (ESummaryWeatherPressure)intg + (((ESummaryWeatherPressure)fract)/100.0);
    } else {  /* *tokp == 'Q' */
        gchar spres[5];
        gint pres;
        
        strncpy(spres, tokp+1, 4);
        spres[4] = 0;
        pres = atoi(spres);
        
        w->pressure = PRESSURE_MBAR_TO_INCH((ESummaryWeatherPressure)pres);
    }
    
    return TRUE;
}

/* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */


static inline gint 
calc_humidity(gdouble temp, 
          gdouble dewp,
          ESummaryWeatherUnits units)
{
    gdouble esat, esurf;
    
    if (units == UNITS_IMPERIAL) {
        temp = TEMP_F_TO_C(temp);
        dewp = TEMP_F_TO_C(dewp);
    }
    
    esat = 6.11 * pow(10.0, (7.5 * temp) / (237.7 + temp));
    esurf = 6.11 * pow(10.0, (7.5 * dewp) / (237.7 + dewp));
    
    return (gint)((esurf/esat) * 100.0);
}

gboolean 
metar_tok_temp (gchar *tokp, 
        Weather *w)
{
    ESummaryWeatherUnits units;
    gchar *ptemp, *pdew, *psep;
    
    if (regexec(&metar_re[TEMP_RE], tokp, 0, NULL, 0) == REG_NOMATCH)
        return FALSE;
    
    if (w->summary->preferences == NULL) {
        units = UNITS_METRIC;
    } else {
        units = w->summary->preferences->units;
    }

    psep = strchr(tokp, '/');
    *psep = 0;
    ptemp = tokp;
    pdew = psep + 1;
    
    if (units == UNITS_IMPERIAL) {
        w->temp = (*ptemp == 'M') ? TEMP_C_TO_F(-atoi(ptemp+1)) :
            TEMP_C_TO_F(atoi(ptemp));
        w->dew = (*pdew == 'M') ? TEMP_C_TO_F(-atoi(pdew+1)) :
            TEMP_C_TO_F(atoi(pdew));
    } else {
        w->temp = (*ptemp == 'M') ? -atoi(ptemp+1) : atoi(ptemp);
        w->dew = (*pdew == 'M') ? -atoi(pdew+1) : atoi (pdew);
    }

    w->humidity = calc_humidity(w->temp, w->dew, units);
    return TRUE;
}

gboolean 
metar_tok_cond (gchar *tokp, 
        Weather *w)
{
    char squal[3], sphen[4];
    char *pphen;
    
    if (regexec(&metar_re[COND_RE], tokp, 0, NULL, 0) == REG_NOMATCH)
        return FALSE;
    
    if ((strlen(tokp) > 3) && ((*tokp == '+') || (*tokp == '-')))
        ++tokp;   /* FIX */
    
    if ((*tokp == '+') || (*tokp == '-'))
        pphen = tokp + 1;
    else if (strlen(tokp) < 4)
        pphen = tokp;
    else
        pphen = tokp + 2;
    
    memset(squal, 0, sizeof(squal));
    strncpy(squal, tokp, pphen - tokp);
    squal[pphen - tokp] = 0;
    
    memset(sphen, 0, sizeof(sphen));
    strncpy(sphen, pphen, sizeof(sphen));
    sphen[sizeof(sphen)-1] = '\0';
    
    /* Defaults */
    w->cond.qualifier = QUALIFIER_NONE;
    w->cond.phenomenon = PHENOMENON_NONE;
    w->cond.significant = FALSE;
    
    if (!strcmp(squal, "")) {
        w->cond.qualifier = QUALIFIER_MODERATE;
    } else if (!strcmp(squal, "-")) {
        w->cond.qualifier = QUALIFIER_LIGHT;
    } else if (!strcmp(squal, "+")) {
        w->cond.qualifier = QUALIFIER_HEAVY;
    } else if (!strcmp(squal, "VC")) {
        w->cond.qualifier = QUALIFIER_VICINITY;
    } else if (!strcmp(squal, "MI")) {
        w->cond.qualifier = QUALIFIER_SHALLOW;
    } else if (!strcmp(squal, "BC")) {
        w->cond.qualifier = QUALIFIER_PATCHES;
    } else if (!strcmp(squal, "PR")) {
        w->cond.qualifier = QUALIFIER_PARTIAL;
    } else if (!strcmp(squal, "TS")) {
        w->cond.qualifier = QUALIFIER_THUNDERSTORM;
    } else if (!strcmp(squal, "BL")) {
        w->cond.qualifier = QUALIFIER_BLOWING;
    } else if (!strcmp(squal, "SH")) {
        w->cond.qualifier = QUALIFIER_SHOWERS;
    } else if (!strcmp(squal, "DR")) {
        w->cond.qualifier = QUALIFIER_DRIFTING;
    } else if (!strcmp(squal, "FZ")) {
        w->cond.qualifier = QUALIFIER_FREEZING;
    } else {
        g_return_val_if_fail(FALSE, FALSE);
    }
    
    if (!strcmp(sphen, "DZ")) {
        w->cond.phenomenon = PHENOMENON_DRIZZLE;
    } else if (!strcmp(sphen, "RA")) {
        w->cond.phenomenon = PHENOMENON_RAIN;
    } else if (!strcmp(sphen, "SN")) {
        w->cond.phenomenon = PHENOMENON_SNOW;
    } else if (!strcmp(sphen, "SG")) {
        w->cond.phenomenon = PHENOMENON_SNOW_GRAINS;
    } else if (!strcmp(sphen, "IC")) {
        w->cond.phenomenon = PHENOMENON_ICE_CRYSTALS;
    } else if (!strcmp(sphen, "PE")) {
        w->cond.phenomenon = PHENOMENON_ICE_PELLETS;
    } else if (!strcmp(sphen, "GR")) {
        w->cond.phenomenon = PHENOMENON_HAIL;
    } else if (!strcmp(sphen, "GS")) {
        w->cond.phenomenon = PHENOMENON_SMALL_HAIL;
    } else if (!strcmp(sphen, "UP")) {
        w->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION;
    } else if (!strcmp(sphen, "BR")) {
        w->cond.phenomenon = PHENOMENON_MIST;
    } else if (!strcmp(sphen, "FG")) {
        w->cond.phenomenon = PHENOMENON_FOG;
    } else if (!strcmp(sphen, "FU")) {
        w->cond.phenomenon = PHENOMENON_SMOKE;
    } else if (!strcmp(sphen, "VA")) {
        w->cond.phenomenon = PHENOMENON_VOLCANIC_ASH;
    } else if (!strcmp(sphen, "SA")) {
        w->cond.phenomenon = PHENOMENON_SAND;
    } else if (!strcmp(sphen, "HZ")) {
        w->cond.phenomenon = PHENOMENON_HAZE;
    } else if (!strcmp(sphen, "PY")) {
        w->cond.phenomenon = PHENOMENON_SPRAY;
    } else if (!strcmp(sphen, "DU")) {
        w->cond.phenomenon = PHENOMENON_DUST;
    } else if (!strcmp(sphen, "SQ")) {
        w->cond.phenomenon = PHENOMENON_SQUALL;
    } else if (!strcmp(sphen, "SS")) {
        w->cond.phenomenon = PHENOMENON_SANDSTORM;
    } else if (!strcmp(sphen, "DS")) {
        w->cond.phenomenon = PHENOMENON_DUSTSTORM;
    } else if (!strcmp(sphen, "PO")) {
        w->cond.phenomenon = PHENOMENON_DUST_WHIRLS;
    } else if (!strcmp(sphen, "+FC")) {
        w->cond.phenomenon = PHENOMENON_TORNADO;
    } else if (!strcmp(sphen, "FC")) {
        w->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD;
    } else {
        g_return_val_if_fail(FALSE, FALSE);
    }
    
    if ((w->cond.qualifier != QUALIFIER_NONE) || (w->cond.phenomenon != PHENOMENON_NONE))
        w->cond.significant = TRUE;
    
    return TRUE;
}

const char *
icon_from_weather (Weather *w)
{
    ESummaryWeatherConditions cond = w->cond;
    ESummaryWeatherSky sky = w->sky;

    switch (cond.phenomenon) {
    case PHENOMENON_DRIZZLE:
    case PHENOMENON_RAIN:
    case PHENOMENON_UNKNOWN_PRECIPITATION:
    case PHENOMENON_HAIL:
    case PHENOMENON_SMALL_HAIL:
        return "myweather-rain.png";
    case PHENOMENON_SNOW:
    case PHENOMENON_SNOW_GRAINS:
    case PHENOMENON_ICE_PELLETS:
    case PHENOMENON_ICE_CRYSTALS:
        return "myweather-snow.png";
    case PHENOMENON_TORNADO:
    case PHENOMENON_SQUALL:
        return "myweather-storm.png";
    case PHENOMENON_MIST:
    case PHENOMENON_FOG:
    case PHENOMENON_SMOKE:
    case PHENOMENON_VOLCANIC_ASH:
    case PHENOMENON_SAND:
    case PHENOMENON_HAZE:
    case PHENOMENON_SPRAY:
    case PHENOMENON_DUST:
    case PHENOMENON_SANDSTORM:
    case PHENOMENON_DUSTSTORM:
    case PHENOMENON_FUNNEL_CLOUD:
    case PHENOMENON_DUST_WHIRLS:
        return "myweather-fog.png";
    default:
        break;
    }

    switch (sky) {
    case SKY_CLEAR:
        return "myweather-sun.png";
    case SKY_BROKEN:
    case SKY_SCATTERED:
    case SKY_FEW:
        return "myweather-suncloud.png";
    case SKY_OVERCAST:
        return "myweather-clouds.png";
    default:
        break;
    }

    return "es-weather.png";
}