/* * metar.c: Metar decoding routines. * * Originally written by Papadimitriou Spiros */ #include #include #include #include #include #include #include #include #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) ? _("\260F") : _("\260C")) #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_("Smoke w/ thunders"), 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_("Volcanic ash w/ thunders"), 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_("Sprays"), N_("Sprays in the vicinity") , N_("Light sprays"), N_("Moderate sprays"), N_("Heavy sprays"), N_("Shallow sprays"), N_("Patches of sprays"), N_("Partial sprays"), "??", N_("Blowing sprays"), "??", N_("Drifting sprays"), N_("Freezing sprays") }, /* 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 */ 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"; }