diff --git a/2023-04-15-085509-5864-1@d1e1b1d5ea6f_master/index.html b/2023-04-15-085509-5864-1@d1e1b1d5ea6f_master/index.html new file mode 100644 index 00000000..8ccd03d4 --- /dev/null +++ b/2023-04-15-085509-5864-1@d1e1b1d5ea6f_master/index.html @@ -0,0 +1,133 @@ + +
+User: | root@888d89d970fc |
---|---|
Working Directory: | /rootdir |
Command Line: | make -j 2 |
Clang Version: | clang version 15.0.7 (Fedora 15.0.7-2.fc37) + |
Date: | Sat Apr 15 08:55:09 2023 |
Bug Type | Quantity | Display? |
All Bugs | 11 | |
Logic error | ||
---|---|---|
Dereference of null pointer | 1 | |
Out-of-bound access | 2 | |
Security | ||
Potential insecure memory buffer bounds restriction in call 'strcpy' | 1 | |
Unix Stream API Error | ||
Resource Leak | 1 | |
Unused code | ||
Dead assignment | 2 | |
Dead initialization | 2 | |
Unreachable code | 2 |
Bug Group | +Bug Type ▾ | +File | +Function/Method | +Line | +Path Length | ++ + |
Unused code | Dead assignment | weather.c | _weather_info_fill | 495 | 1 | View Report | + +
Unused code | Dead assignment | weather-metar.c | metar_parse | 454 | 1 | View Report | + +
Unused code | Dead initialization | weather-sun.c | calc_sun2 | 163 | 1 | View Report | + +
Unused code | Dead initialization | weather-sun.c | calc_sun2 | 162 | 1 | View Report | + +
Logic error | Dereference of null pointer | weather-met.c | met_reprocess | 111 | 27 | View Report | + +
Logic error | Out-of-bound access | weather-met.c | met_reprocess | 111 | 48 | View Report | + +
Logic error | Out-of-bound access | weather-metar.c | metar_tok_vis | 169 | 9 | View Report | + +
Security | Potential insecure memory buffer bounds restriction in call 'strcpy' | weather.c | weather_info_get_update | 719 | 1 | View Report | + +
Unix Stream API Error | Resource Leak | test_metar.c | main | 73 | 8 | View Report | + +
Unused code | Unreachable code | weather-metar.c | metar_tok_vis | 177 | 1 | View Report | + +
Unused code | Unreachable code | weather-sun.c | weather_info_next_sun_event | 335 | 1 | View Report | + +
File: | weather-met.c |
Warning: | line 111, column 8 Out of bound memory access (access exceeds upper limit of memory block) |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ | |||
2 | /* weather-met.c - UK Met Office forecast source | |||
3 | * | |||
4 | * This program is free software; you can redistribute it and/or | |||
5 | * modify it under the terms of the GNU General Public License as | |||
6 | * published by the Free Software Foundation; either version 2 of the | |||
7 | * License, or (at your option) any later version. | |||
8 | * | |||
9 | * This program is distributed in the hope that it will be useful, but | |||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
12 | * General Public License for more details. | |||
13 | * | |||
14 | * You should have received a copy of the GNU General Public License | |||
15 | * along with this program; if not, see | |||
16 | * <http://www.gnu.org/licenses/>. | |||
17 | */ | |||
18 | ||||
19 | #ifdef HAVE_CONFIG_H1 | |||
20 | #include <config.h> | |||
21 | #endif | |||
22 | ||||
23 | #include <ctype.h> | |||
24 | #include <stdlib.h> | |||
25 | #include <string.h> | |||
26 | ||||
27 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE | |||
28 | #include "weather.h" | |||
29 | #include "weather-priv.h" | |||
30 | ||||
31 | static char * | |||
32 | met_reprocess (char *x, int len) | |||
33 | { | |||
34 | char *p = x; | |||
35 | char *o; | |||
36 | int spacing = 0; | |||
37 | static gchar *buf; | |||
38 | static gint buflen = 0; | |||
39 | gchar *lastspace = NULL((void*)0); | |||
40 | int count = 0; | |||
41 | ||||
42 | if (buflen < len) | |||
43 | { | |||
44 | if (buf
| |||
45 | g_free (buf); | |||
46 | buf = g_malloc (len + 1); | |||
47 | buflen = len; | |||
48 | } | |||
49 | ||||
50 | o = buf; | |||
51 | x += len; /* End mark */ | |||
52 | ||||
53 | while (*p && p
| |||
54 | if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) { | |||
55 | if (!spacing) { | |||
56 | spacing = 1; | |||
57 | lastspace = o; | |||
58 | count++; | |||
59 | *o++ = ' '; | |||
60 | } | |||
61 | p++; | |||
62 | continue; | |||
63 | } | |||
64 | spacing = 0; | |||
65 | if (count
| |||
66 | count = o - lastspace - 1; | |||
67 | *lastspace = '\n'; | |||
68 | lastspace = NULL((void*)0); | |||
69 | } | |||
70 | ||||
71 | if (*p == '&') { | |||
72 | if (g_ascii_strncasecmp (p, "&", 5) == 0) { | |||
73 | *o++ = '&'; | |||
74 | count++; | |||
75 | p += 5; | |||
76 | continue; | |||
77 | } | |||
78 | if (g_ascii_strncasecmp (p, "<", 4) == 0) { | |||
79 | *o++ = '<'; | |||
80 | count++; | |||
81 | p += 4; | |||
82 | continue; | |||
83 | } | |||
84 | if (g_ascii_strncasecmp (p, ">", 4) == 0) { | |||
85 | *o++ = '>'; | |||
86 | count++; | |||
87 | p += 4; | |||
88 | continue; | |||
89 | } | |||
90 | } | |||
91 | if (*p == '<') { | |||
92 | if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) { | |||
93 | *o++ = '\n'; | |||
94 | count = 0; | |||
95 | } | |||
96 | if (g_ascii_strncasecmp (p, "<B>", 3) == 0) { | |||
97 | *o++ = '\n'; | |||
98 | *o++ = '\n'; | |||
99 | count = 0; | |||
100 | } | |||
101 | p++; | |||
102 | while (*p && *p != '>') | |||
103 | p++; | |||
104 | if (*p) | |||
105 | p++; | |||
106 | continue; | |||
107 | } | |||
108 | *o++ = *p++; | |||
109 | count++; | |||
110 | } | |||
111 | *o = 0; | |||
| ||||
112 | return buf; | |||
113 | } | |||
114 | ||||
115 | /* | |||
116 | * Parse the metoffice forecast info. | |||
117 | * For mate 3.0 we want to just embed an HTML matecomponent component and | |||
118 | * be done with this ;) | |||
119 | */ | |||
120 | ||||
121 | static gchar * | |||
122 | met_parse (const gchar *meto) | |||
123 | { | |||
124 | gchar *p; | |||
125 | gchar *rp; | |||
126 | gchar *r = g_strdup ("Met Office Forecast\n"); | |||
127 | gchar *t; | |||
128 | ||||
129 | g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "meto != NULL"); return (r); } } while (0); | |||
130 | ||||
131 | p = strstr (meto, "Summary: </b>"); | |||
132 | g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "p != NULL"); return (r); } } while (0); | |||
133 | ||||
134 | rp = strstr (p, "Text issued at:"); | |||
135 | g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "rp != NULL"); return (r); } } while (0); | |||
136 | ||||
137 | p += 13; | |||
138 | /* p to rp is the text block we want but in HTML malformat */ | |||
139 | t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0)); | |||
140 | g_free (r); | |||
141 | ||||
142 | return t; | |||
143 | } | |||
144 | ||||
145 | static void | |||
146 | met_finish (SoupSession *session, SoupMessage *msg, gpointer data) | |||
147 | { | |||
148 | WeatherInfo *info = (WeatherInfo *)data; | |||
149 | ||||
150 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); | |||
| ||||
151 | ||||
152 | if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code ) < 300)) { | |||
153 | g_warning ("Failed to get Met Office forecast data: %d %s.\n", | |||
154 | msg->status_code, msg->reason_phrase); | |||
155 | request_done (info, FALSE(0)); | |||
156 | return; | |||
157 | } | |||
158 | ||||
159 | info->forecast = met_parse (msg->response_body->data); | |||
160 | request_done (info, TRUE(!(0))); | |||
161 | } | |||
162 | ||||
163 | void | |||
164 | metoffice_start_open (WeatherInfo *info) | |||
165 | { | |||
166 | gchar *url; | |||
167 | SoupMessage *msg; | |||
168 | WeatherLocation *loc; | |||
169 | ||||
170 | loc = info->location; | |||
171 | url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1); | |||
172 | ||||
173 | msg = soup_message_new ("GET", url); | |||
174 | soup_session_queue_message (info->session, msg, met_finish, info); | |||
175 | g_free (url); | |||
176 | ||||
177 | info->requests_pending++; | |||
178 | } |
File: | weather-sun.c |
Warning: | line 163, column 13 Value stored to 'obsLon' during its initialization is never read |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | /* weather-sun.c - Astronomy calculations for mateweather |
3 | * |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License as |
6 | * published by the Free Software Foundation; either version 2 of the |
7 | * License, or (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, see |
16 | * <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | /* |
20 | * Formulas from: |
21 | * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith |
22 | * Cambridge University Press 1988 |
23 | * Unless otherwise noted, comments referencing "steps" are related to |
24 | * the algorithm presented in section 49 of above |
25 | */ |
26 | |
27 | #ifdef HAVE_CONFIG_H1 |
28 | #include <config.h> |
29 | #endif |
30 | |
31 | #include <math.h> |
32 | #include <time.h> |
33 | #include <glib.h> |
34 | |
35 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE |
36 | #include "weather-priv.h" |
37 | |
38 | #define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392) |
39 | |
40 | /* |
41 | * Ecliptic longitude of the sun at specified time (UT) |
42 | * The algoithm is described in section 47 of Duffett-Smith |
43 | * Return value is in radians |
44 | */ |
45 | gdouble |
46 | sunEclipLongitude(time_t t) |
47 | { |
48 | gdouble ndays, meanAnom, eccenAnom, delta, e, longitude; |
49 | |
50 | /* |
51 | * Start with an estimate based on a fixed daily rate |
52 | */ |
53 | ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.; |
54 | meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846 ) |
55 | - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846 ); |
56 | |
57 | /* |
58 | * Approximate solution of Kepler's equation: |
59 | * Find E which satisfies E - e sin(E) = M (mean anomaly) |
60 | */ |
61 | eccenAnom = meanAnom; |
62 | e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392); |
63 | |
64 | while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom)) |
65 | { |
66 | eccenAnom -= delta / (1.- e * cos(eccenAnom)); |
67 | } |
68 | |
69 | /* |
70 | * Earth's longitude on the ecliptic |
71 | */ |
72 | longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180. ) * 3.14159265358979323846) |
73 | + 2. * atan (sqrt ((1.+e)/(1.-e)) |
74 | * tan (eccenAnom / 2.)), |
75 | 2. * M_PI3.14159265358979323846); |
76 | if (longitude < 0.) { |
77 | longitude += 2 * M_PI3.14159265358979323846; |
78 | } |
79 | return longitude; |
80 | } |
81 | |
82 | static gdouble |
83 | ecliptic_obliquity (gdouble time) |
84 | { |
85 | gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.); |
86 | gdouble eclip_secs = (84381.448 |
87 | - (46.84024 * jc) |
88 | - (59.e-5 * jc * jc) |
89 | + (1.813e-3 * jc * jc * jc)); |
90 | return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846 ); |
91 | } |
92 | |
93 | /* |
94 | * Convert ecliptic longitude and latitude (radians) to equitorial |
95 | * coordinates, expressed as right ascension (hours) and |
96 | * declination (radians) |
97 | */ |
98 | void |
99 | ecl2equ (gdouble time, |
100 | gdouble eclipLon, gdouble eclipLat, |
101 | gdouble *ra, gdouble *decl) |
102 | { |
103 | gdouble mEclipObliq = ecliptic_obliquity(time); |
104 | |
105 | if (ra) { |
106 | *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat) * sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846 ) |
107 | - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat) * sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846 ) |
108 | cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat) * sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846 ); |
109 | if (*ra < 0.) |
110 | *ra += 24.; |
111 | } |
112 | if (decl) { |
113 | *decl = asin (( sin (eclipLat) * cos (mEclipObliq)) |
114 | + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon)); |
115 | } |
116 | } |
117 | |
118 | /* |
119 | * Calculate rising and setting times for an object |
120 | * based on it equitorial coordinates (section 33 & 15) |
121 | * Returned "rise" and "set" values are sideral times in hours |
122 | */ |
123 | static void |
124 | gstObsv (gdouble ra, gdouble decl, |
125 | gdouble obsLat, gdouble obsLon, |
126 | gdouble *rise, gdouble *set) |
127 | { |
128 | double a = acos (-tan (obsLat) * tan (decl)); |
129 | double b; |
130 | |
131 | if (isnan (a)__builtin_isnan (a) != 0) { |
132 | *set = *rise = a; |
133 | return; |
134 | } |
135 | a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846); |
136 | b = 24. - a + ra; |
137 | a += ra; |
138 | a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846); |
139 | b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846); |
140 | if ((a = fmod (a, 24.)) < 0) |
141 | a += 24.; |
142 | if ((b = fmod (b, 24.)) < 0) |
143 | b += 24.; |
144 | |
145 | *set = a; |
146 | *rise = b; |
147 | } |
148 | |
149 | static gdouble |
150 | t0 (time_t date) |
151 | { |
152 | gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0; |
153 | gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.); |
154 | if (t0 < 0.) |
155 | t0 += 24.; |
156 | return t0; |
157 | } |
158 | |
159 | static gboolean |
160 | calc_sun2 (WeatherInfo *info, time_t t) |
161 | { |
162 | gdouble obsLat = info->location->latitude; |
163 | gdouble obsLon = info->location->longitude; |
Value stored to 'obsLon' during its initialization is never read | |
164 | time_t gm_midn; |
165 | time_t lcl_midn; |
166 | gdouble gm_hoff, lambda; |
167 | gdouble ra1, ra2; |
168 | gdouble decl1, decl2; |
169 | gdouble decl_midn, decl_noon; |
170 | gdouble rise1, rise2; |
171 | gdouble set1, set2; |
172 | gdouble tt, t00; |
173 | gdouble x, u, dt; |
174 | |
175 | /* Approximate preceding local midnight at observer's longitude */ |
176 | obsLat = info->location->latitude; |
177 | obsLon = info->location->longitude; |
178 | gm_midn = t - (t % 86400); |
179 | gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.); |
180 | lcl_midn = gm_midn - 3600. * gm_hoff; |
181 | if (t - lcl_midn >= 86400) |
182 | lcl_midn += 86400; |
183 | else if (lcl_midn > t) |
184 | lcl_midn -= 86400; |
185 | |
186 | lambda = sunEclipLongitude (lcl_midn); |
187 | |
188 | /* |
189 | * Calculate equitorial coordinates of sun at previous |
190 | * and next local midnights |
191 | */ |
192 | ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1); |
193 | ecl2equ (lcl_midn + 86400., |
194 | lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846 ), 0., |
195 | &ra2, &decl2); |
196 | |
197 | /* |
198 | * If the observer is within the Arctic or Antarctic Circles then |
199 | * the sun may be above or below the horizon for the full day. |
200 | */ |
201 | decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2)); |
202 | decl_noon = (decl1+decl2)/2.; |
203 | info->midnightSun = |
204 | (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn)); |
205 | info->polarNight = |
206 | (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon)); |
207 | if (info->midnightSun || info->polarNight) { |
208 | info->sunriseValid = info->sunsetValid = FALSE(0); |
209 | return FALSE(0); |
210 | } |
211 | |
212 | /* |
213 | * Convert to rise and set times based positions for the preceding |
214 | * and following local midnights. |
215 | */ |
216 | gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1); |
217 | gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2); |
218 | |
219 | /* TODO: include calculations for regions near the poles. */ |
220 | if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) { |
221 | info->sunriseValid = info->sunsetValid = FALSE(0); |
222 | return FALSE(0); |
223 | } |
224 | |
225 | if (rise2 < rise1) { |
226 | rise2 += 24.; |
227 | } |
228 | if (set2 < set1) { |
229 | set2 += 24.; |
230 | } |
231 | |
232 | tt = t0(lcl_midn); |
233 | t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909; |
234 | |
235 | if (t00 < 0.) |
236 | t00 += 24.; |
237 | |
238 | if (rise1 < t00) { |
239 | rise1 += 24.; |
240 | rise2 += 24.; |
241 | } |
242 | if (set1 < t00) { |
243 | set1 += 24.; |
244 | set2 += 24.; |
245 | } |
246 | |
247 | /* |
248 | * Interpolate between the two to get a rise and set time |
249 | * based on the sun's position at local noon (step 8) |
250 | */ |
251 | rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2); |
252 | set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2); |
253 | |
254 | /* |
255 | * Calculate an adjustment value to account for parallax, |
256 | * refraction and the Sun's finite diameter (steps 9,10) |
257 | */ |
258 | decl2 = (decl1 + decl2) / 2.; |
259 | x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846); |
260 | u = acos ( sin(obsLat) / cos(decl2) ); |
261 | dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846 ); |
262 | |
263 | /* |
264 | * Subtract the correction value from sunrise and add to sunset, |
265 | * then (step 11) convert sideral times to UT |
266 | */ |
267 | rise1 = (rise1 - dt - tt) * 0.9972695661; |
268 | if (rise1 < 0.) |
269 | rise1 += 24; |
270 | else if (rise1 >= 24.) |
271 | rise1 -= 24.; |
272 | info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.)); |
273 | info->sunrise = (rise1 * 3600.) + lcl_midn; |
274 | |
275 | set1 = (set1 + dt - tt) * 0.9972695661; |
276 | if (set1 < 0.) |
277 | set1 += 24; |
278 | else if (set1 >= 24.) |
279 | set1 -= 24.; |
280 | info->sunsetValid = ((set1 >= 0.) && (set1 < 24.)); |
281 | info->sunset = (set1 * 3600.) + lcl_midn; |
282 | |
283 | return (info->sunriseValid || info->sunsetValid); |
284 | } |
285 | |
286 | /** |
287 | * calc_sun_time: |
288 | * @info: #WeatherInfo structure containing the observer's latitude |
289 | * and longitude in radians, fills in the sunrise and sunset times. |
290 | * @t: time_t |
291 | * |
292 | * Returns: gboolean indicating if the results are valid. |
293 | */ |
294 | gboolean |
295 | calc_sun_time (WeatherInfo *info, time_t t) |
296 | { |
297 | return info->location->latlon_valid && calc_sun2 (info, t); |
298 | } |
299 | |
300 | /** |
301 | * calc_sun: |
302 | * @info: #WeatherInfo structure containing the observer's latitude |
303 | * and longitude in radians, fills in the sunrise and sunset times. |
304 | * |
305 | * Returns: gboolean indicating if the results are valid. |
306 | */ |
307 | gboolean |
308 | calc_sun (WeatherInfo *info) |
309 | { |
310 | return calc_sun_time(info, time(NULL((void*)0))); |
311 | } |
312 | |
313 | /** |
314 | * weather_info_next_sun_event: |
315 | * @info: #WeatherInfo structure |
316 | * |
317 | * Returns: the interval, in seconds, until the next "sun event": |
318 | * - local midnight, when rise and set times are recomputed |
319 | * - next sunrise, when icon changes to daytime version |
320 | * - next sunset, when icon changes to nighttime version |
321 | */ |
322 | gint |
323 | weather_info_next_sun_event (WeatherInfo *info) |
324 | { |
325 | time_t now = time (NULL((void*)0)); |
326 | struct tm ltm; |
327 | time_t nxtEvent; |
328 | |
329 | g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (-1); } } while (0); |
330 | |
331 | if (!calc_sun (info)) |
332 | return -1; |
333 | |
334 | /* Determine when the next local midnight occurs */ |
335 | (void) localtime_r (&now, <m); |
336 | ltm.tm_sec = 0; |
337 | ltm.tm_min = 0; |
338 | ltm.tm_hour = 0; |
339 | ltm.tm_mday++; |
340 | nxtEvent = mktime (<m); |
341 | |
342 | if (info->sunsetValid && |
343 | (info->sunset > now) && (info->sunset < nxtEvent)) |
344 | nxtEvent = info->sunset; |
345 | if (info->sunriseValid && |
346 | (info->sunrise > now) && (info->sunrise < nxtEvent)) |
347 | nxtEvent = info->sunrise; |
348 | return (gint)(nxtEvent - now); |
349 | } |
File: | weather-met.c |
Warning: | line 111, column 8 Dereference of null pointer (loaded from variable 'o') |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ | |||
2 | /* weather-met.c - UK Met Office forecast source | |||
3 | * | |||
4 | * This program is free software; you can redistribute it and/or | |||
5 | * modify it under the terms of the GNU General Public License as | |||
6 | * published by the Free Software Foundation; either version 2 of the | |||
7 | * License, or (at your option) any later version. | |||
8 | * | |||
9 | * This program is distributed in the hope that it will be useful, but | |||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
12 | * General Public License for more details. | |||
13 | * | |||
14 | * You should have received a copy of the GNU General Public License | |||
15 | * along with this program; if not, see | |||
16 | * <http://www.gnu.org/licenses/>. | |||
17 | */ | |||
18 | ||||
19 | #ifdef HAVE_CONFIG_H1 | |||
20 | #include <config.h> | |||
21 | #endif | |||
22 | ||||
23 | #include <ctype.h> | |||
24 | #include <stdlib.h> | |||
25 | #include <string.h> | |||
26 | ||||
27 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE | |||
28 | #include "weather.h" | |||
29 | #include "weather-priv.h" | |||
30 | ||||
31 | static char * | |||
32 | met_reprocess (char *x, int len) | |||
33 | { | |||
34 | char *p = x; | |||
35 | char *o; | |||
36 | int spacing = 0; | |||
37 | static gchar *buf; | |||
38 | static gint buflen = 0; | |||
39 | gchar *lastspace = NULL((void*)0); | |||
40 | int count = 0; | |||
41 | ||||
42 | if (buflen < len) | |||
43 | { | |||
44 | if (buf) | |||
45 | g_free (buf); | |||
46 | buf = g_malloc (len + 1); | |||
47 | buflen = len; | |||
48 | } | |||
49 | ||||
50 | o = buf; | |||
51 | x += len; /* End mark */ | |||
52 | ||||
53 | while (*p && p < x) { | |||
54 | if (g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) { | |||
55 | if (!spacing) { | |||
56 | spacing = 1; | |||
57 | lastspace = o; | |||
58 | count++; | |||
59 | *o++ = ' '; | |||
60 | } | |||
61 | p++; | |||
62 | continue; | |||
63 | } | |||
64 | spacing = 0; | |||
65 | if (count > 75 && lastspace) { | |||
66 | count = o - lastspace - 1; | |||
67 | *lastspace = '\n'; | |||
68 | lastspace = NULL((void*)0); | |||
69 | } | |||
70 | ||||
71 | if (*p == '&') { | |||
72 | if (g_ascii_strncasecmp (p, "&", 5) == 0) { | |||
73 | *o++ = '&'; | |||
74 | count++; | |||
75 | p += 5; | |||
76 | continue; | |||
77 | } | |||
78 | if (g_ascii_strncasecmp (p, "<", 4) == 0) { | |||
79 | *o++ = '<'; | |||
80 | count++; | |||
81 | p += 4; | |||
82 | continue; | |||
83 | } | |||
84 | if (g_ascii_strncasecmp (p, ">", 4) == 0) { | |||
85 | *o++ = '>'; | |||
86 | count++; | |||
87 | p += 4; | |||
88 | continue; | |||
89 | } | |||
90 | } | |||
91 | if (*p == '<') { | |||
92 | if (g_ascii_strncasecmp (p, "<BR>", 4) == 0) { | |||
93 | *o++ = '\n'; | |||
94 | count = 0; | |||
95 | } | |||
96 | if (g_ascii_strncasecmp (p, "<B>", 3) == 0) { | |||
97 | *o++ = '\n'; | |||
98 | *o++ = '\n'; | |||
99 | count = 0; | |||
100 | } | |||
101 | p++; | |||
102 | while (*p && *p != '>') | |||
103 | p++; | |||
104 | if (*p) | |||
105 | p++; | |||
106 | continue; | |||
107 | } | |||
108 | *o++ = *p++; | |||
109 | count++; | |||
110 | } | |||
111 | *o = 0; | |||
| ||||
112 | return buf; | |||
113 | } | |||
114 | ||||
115 | /* | |||
116 | * Parse the metoffice forecast info. | |||
117 | * For mate 3.0 we want to just embed an HTML matecomponent component and | |||
118 | * be done with this ;) | |||
119 | */ | |||
120 | ||||
121 | static gchar * | |||
122 | met_parse (const gchar *meto) | |||
123 | { | |||
124 | gchar *p; | |||
125 | gchar *rp; | |||
126 | gchar *r = g_strdup ("Met Office Forecast\n"); | |||
127 | gchar *t; | |||
128 | ||||
129 | g_return_val_if_fail (meto != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (meto != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "meto != NULL"); return (r); } } while (0); | |||
130 | ||||
131 | p = strstr (meto, "Summary: </b>"); | |||
132 | g_return_val_if_fail (p != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (p != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "p != NULL"); return (r); } } while (0); | |||
133 | ||||
134 | rp = strstr (p, "Text issued at:"); | |||
135 | g_return_val_if_fail (rp != NULL, r)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (rp != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "rp != NULL"); return (r); } } while (0); | |||
136 | ||||
137 | p += 13; | |||
138 | /* p to rp is the text block we want but in HTML malformat */ | |||
139 | t = g_strconcat (r, met_reprocess (p, rp - p), NULL((void*)0)); | |||
140 | g_free (r); | |||
141 | ||||
142 | return t; | |||
143 | } | |||
144 | ||||
145 | static void | |||
146 | met_finish (SoupSession *session, SoupMessage *msg, gpointer data) | |||
147 | { | |||
148 | WeatherInfo *info = (WeatherInfo *)data; | |||
149 | ||||
150 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); | |||
| ||||
151 | ||||
152 | if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code ) < 300)) { | |||
153 | g_warning ("Failed to get Met Office forecast data: %d %s.\n", | |||
154 | msg->status_code, msg->reason_phrase); | |||
155 | request_done (info, FALSE(0)); | |||
156 | return; | |||
157 | } | |||
158 | ||||
159 | info->forecast = met_parse (msg->response_body->data); | |||
160 | request_done (info, TRUE(!(0))); | |||
161 | } | |||
162 | ||||
163 | void | |||
164 | metoffice_start_open (WeatherInfo *info) | |||
165 | { | |||
166 | gchar *url; | |||
167 | SoupMessage *msg; | |||
168 | WeatherLocation *loc; | |||
169 | ||||
170 | loc = info->location; | |||
171 | url = g_strdup_printf ("http://www.metoffice.gov.uk/weather/europe/uk/%s.html", loc->zone + 1); | |||
172 | ||||
173 | msg = soup_message_new ("GET", url); | |||
174 | soup_session_queue_message (info->session, msg, met_finish, info); | |||
175 | g_free (url); | |||
176 | ||||
177 | info->requests_pending++; | |||
178 | } |
File: | weather-sun.c |
Warning: | line 162, column 13 Value stored to 'obsLat' during its initialization is never read |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | /* weather-sun.c - Astronomy calculations for mateweather |
3 | * |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License as |
6 | * published by the Free Software Foundation; either version 2 of the |
7 | * License, or (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, see |
16 | * <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | /* |
20 | * Formulas from: |
21 | * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith |
22 | * Cambridge University Press 1988 |
23 | * Unless otherwise noted, comments referencing "steps" are related to |
24 | * the algorithm presented in section 49 of above |
25 | */ |
26 | |
27 | #ifdef HAVE_CONFIG_H1 |
28 | #include <config.h> |
29 | #endif |
30 | |
31 | #include <math.h> |
32 | #include <time.h> |
33 | #include <glib.h> |
34 | |
35 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE |
36 | #include "weather-priv.h" |
37 | |
38 | #define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392) |
39 | |
40 | /* |
41 | * Ecliptic longitude of the sun at specified time (UT) |
42 | * The algoithm is described in section 47 of Duffett-Smith |
43 | * Return value is in radians |
44 | */ |
45 | gdouble |
46 | sunEclipLongitude(time_t t) |
47 | { |
48 | gdouble ndays, meanAnom, eccenAnom, delta, e, longitude; |
49 | |
50 | /* |
51 | * Start with an estimate based on a fixed daily rate |
52 | */ |
53 | ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.; |
54 | meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846 ) |
55 | - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846 ); |
56 | |
57 | /* |
58 | * Approximate solution of Kepler's equation: |
59 | * Find E which satisfies E - e sin(E) = M (mean anomaly) |
60 | */ |
61 | eccenAnom = meanAnom; |
62 | e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392); |
63 | |
64 | while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom)) |
65 | { |
66 | eccenAnom -= delta / (1.- e * cos(eccenAnom)); |
67 | } |
68 | |
69 | /* |
70 | * Earth's longitude on the ecliptic |
71 | */ |
72 | longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180. ) * 3.14159265358979323846) |
73 | + 2. * atan (sqrt ((1.+e)/(1.-e)) |
74 | * tan (eccenAnom / 2.)), |
75 | 2. * M_PI3.14159265358979323846); |
76 | if (longitude < 0.) { |
77 | longitude += 2 * M_PI3.14159265358979323846; |
78 | } |
79 | return longitude; |
80 | } |
81 | |
82 | static gdouble |
83 | ecliptic_obliquity (gdouble time) |
84 | { |
85 | gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.); |
86 | gdouble eclip_secs = (84381.448 |
87 | - (46.84024 * jc) |
88 | - (59.e-5 * jc * jc) |
89 | + (1.813e-3 * jc * jc * jc)); |
90 | return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846 ); |
91 | } |
92 | |
93 | /* |
94 | * Convert ecliptic longitude and latitude (radians) to equitorial |
95 | * coordinates, expressed as right ascension (hours) and |
96 | * declination (radians) |
97 | */ |
98 | void |
99 | ecl2equ (gdouble time, |
100 | gdouble eclipLon, gdouble eclipLat, |
101 | gdouble *ra, gdouble *decl) |
102 | { |
103 | gdouble mEclipObliq = ecliptic_obliquity(time); |
104 | |
105 | if (ra) { |
106 | *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat) * sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846 ) |
107 | - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat) * sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846 ) |
108 | cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat) * sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846 ); |
109 | if (*ra < 0.) |
110 | *ra += 24.; |
111 | } |
112 | if (decl) { |
113 | *decl = asin (( sin (eclipLat) * cos (mEclipObliq)) |
114 | + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon)); |
115 | } |
116 | } |
117 | |
118 | /* |
119 | * Calculate rising and setting times for an object |
120 | * based on it equitorial coordinates (section 33 & 15) |
121 | * Returned "rise" and "set" values are sideral times in hours |
122 | */ |
123 | static void |
124 | gstObsv (gdouble ra, gdouble decl, |
125 | gdouble obsLat, gdouble obsLon, |
126 | gdouble *rise, gdouble *set) |
127 | { |
128 | double a = acos (-tan (obsLat) * tan (decl)); |
129 | double b; |
130 | |
131 | if (isnan (a)__builtin_isnan (a) != 0) { |
132 | *set = *rise = a; |
133 | return; |
134 | } |
135 | a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846); |
136 | b = 24. - a + ra; |
137 | a += ra; |
138 | a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846); |
139 | b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846); |
140 | if ((a = fmod (a, 24.)) < 0) |
141 | a += 24.; |
142 | if ((b = fmod (b, 24.)) < 0) |
143 | b += 24.; |
144 | |
145 | *set = a; |
146 | *rise = b; |
147 | } |
148 | |
149 | static gdouble |
150 | t0 (time_t date) |
151 | { |
152 | gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0; |
153 | gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.); |
154 | if (t0 < 0.) |
155 | t0 += 24.; |
156 | return t0; |
157 | } |
158 | |
159 | static gboolean |
160 | calc_sun2 (WeatherInfo *info, time_t t) |
161 | { |
162 | gdouble obsLat = info->location->latitude; |
Value stored to 'obsLat' during its initialization is never read | |
163 | gdouble obsLon = info->location->longitude; |
164 | time_t gm_midn; |
165 | time_t lcl_midn; |
166 | gdouble gm_hoff, lambda; |
167 | gdouble ra1, ra2; |
168 | gdouble decl1, decl2; |
169 | gdouble decl_midn, decl_noon; |
170 | gdouble rise1, rise2; |
171 | gdouble set1, set2; |
172 | gdouble tt, t00; |
173 | gdouble x, u, dt; |
174 | |
175 | /* Approximate preceding local midnight at observer's longitude */ |
176 | obsLat = info->location->latitude; |
177 | obsLon = info->location->longitude; |
178 | gm_midn = t - (t % 86400); |
179 | gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.); |
180 | lcl_midn = gm_midn - 3600. * gm_hoff; |
181 | if (t - lcl_midn >= 86400) |
182 | lcl_midn += 86400; |
183 | else if (lcl_midn > t) |
184 | lcl_midn -= 86400; |
185 | |
186 | lambda = sunEclipLongitude (lcl_midn); |
187 | |
188 | /* |
189 | * Calculate equitorial coordinates of sun at previous |
190 | * and next local midnights |
191 | */ |
192 | ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1); |
193 | ecl2equ (lcl_midn + 86400., |
194 | lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846 ), 0., |
195 | &ra2, &decl2); |
196 | |
197 | /* |
198 | * If the observer is within the Arctic or Antarctic Circles then |
199 | * the sun may be above or below the horizon for the full day. |
200 | */ |
201 | decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2)); |
202 | decl_noon = (decl1+decl2)/2.; |
203 | info->midnightSun = |
204 | (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn)); |
205 | info->polarNight = |
206 | (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon)); |
207 | if (info->midnightSun || info->polarNight) { |
208 | info->sunriseValid = info->sunsetValid = FALSE(0); |
209 | return FALSE(0); |
210 | } |
211 | |
212 | /* |
213 | * Convert to rise and set times based positions for the preceding |
214 | * and following local midnights. |
215 | */ |
216 | gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1); |
217 | gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2); |
218 | |
219 | /* TODO: include calculations for regions near the poles. */ |
220 | if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) { |
221 | info->sunriseValid = info->sunsetValid = FALSE(0); |
222 | return FALSE(0); |
223 | } |
224 | |
225 | if (rise2 < rise1) { |
226 | rise2 += 24.; |
227 | } |
228 | if (set2 < set1) { |
229 | set2 += 24.; |
230 | } |
231 | |
232 | tt = t0(lcl_midn); |
233 | t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909; |
234 | |
235 | if (t00 < 0.) |
236 | t00 += 24.; |
237 | |
238 | if (rise1 < t00) { |
239 | rise1 += 24.; |
240 | rise2 += 24.; |
241 | } |
242 | if (set1 < t00) { |
243 | set1 += 24.; |
244 | set2 += 24.; |
245 | } |
246 | |
247 | /* |
248 | * Interpolate between the two to get a rise and set time |
249 | * based on the sun's position at local noon (step 8) |
250 | */ |
251 | rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2); |
252 | set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2); |
253 | |
254 | /* |
255 | * Calculate an adjustment value to account for parallax, |
256 | * refraction and the Sun's finite diameter (steps 9,10) |
257 | */ |
258 | decl2 = (decl1 + decl2) / 2.; |
259 | x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846); |
260 | u = acos ( sin(obsLat) / cos(decl2) ); |
261 | dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846 ); |
262 | |
263 | /* |
264 | * Subtract the correction value from sunrise and add to sunset, |
265 | * then (step 11) convert sideral times to UT |
266 | */ |
267 | rise1 = (rise1 - dt - tt) * 0.9972695661; |
268 | if (rise1 < 0.) |
269 | rise1 += 24; |
270 | else if (rise1 >= 24.) |
271 | rise1 -= 24.; |
272 | info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.)); |
273 | info->sunrise = (rise1 * 3600.) + lcl_midn; |
274 | |
275 | set1 = (set1 + dt - tt) * 0.9972695661; |
276 | if (set1 < 0.) |
277 | set1 += 24; |
278 | else if (set1 >= 24.) |
279 | set1 -= 24.; |
280 | info->sunsetValid = ((set1 >= 0.) && (set1 < 24.)); |
281 | info->sunset = (set1 * 3600.) + lcl_midn; |
282 | |
283 | return (info->sunriseValid || info->sunsetValid); |
284 | } |
285 | |
286 | /** |
287 | * calc_sun_time: |
288 | * @info: #WeatherInfo structure containing the observer's latitude |
289 | * and longitude in radians, fills in the sunrise and sunset times. |
290 | * @t: time_t |
291 | * |
292 | * Returns: gboolean indicating if the results are valid. |
293 | */ |
294 | gboolean |
295 | calc_sun_time (WeatherInfo *info, time_t t) |
296 | { |
297 | return info->location->latlon_valid && calc_sun2 (info, t); |
298 | } |
299 | |
300 | /** |
301 | * calc_sun: |
302 | * @info: #WeatherInfo structure containing the observer's latitude |
303 | * and longitude in radians, fills in the sunrise and sunset times. |
304 | * |
305 | * Returns: gboolean indicating if the results are valid. |
306 | */ |
307 | gboolean |
308 | calc_sun (WeatherInfo *info) |
309 | { |
310 | return calc_sun_time(info, time(NULL((void*)0))); |
311 | } |
312 | |
313 | /** |
314 | * weather_info_next_sun_event: |
315 | * @info: #WeatherInfo structure |
316 | * |
317 | * Returns: the interval, in seconds, until the next "sun event": |
318 | * - local midnight, when rise and set times are recomputed |
319 | * - next sunrise, when icon changes to daytime version |
320 | * - next sunset, when icon changes to nighttime version |
321 | */ |
322 | gint |
323 | weather_info_next_sun_event (WeatherInfo *info) |
324 | { |
325 | time_t now = time (NULL((void*)0)); |
326 | struct tm ltm; |
327 | time_t nxtEvent; |
328 | |
329 | g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (-1); } } while (0); |
330 | |
331 | if (!calc_sun (info)) |
332 | return -1; |
333 | |
334 | /* Determine when the next local midnight occurs */ |
335 | (void) localtime_r (&now, <m); |
336 | ltm.tm_sec = 0; |
337 | ltm.tm_min = 0; |
338 | ltm.tm_hour = 0; |
339 | ltm.tm_mday++; |
340 | nxtEvent = mktime (<m); |
341 | |
342 | if (info->sunsetValid && |
343 | (info->sunset > now) && (info->sunset < nxtEvent)) |
344 | nxtEvent = info->sunset; |
345 | if (info->sunriseValid && |
346 | (info->sunrise > now) && (info->sunrise < nxtEvent)) |
347 | nxtEvent = info->sunrise; |
348 | return (gint)(nxtEvent - now); |
349 | } |
File: | test_metar.c |
Warning: | line 73, column 12 Opened file is never closed; potential resource leak |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * Simple program to reproduce METAR parsing results from command line | |||
4 | */ | |||
5 | ||||
6 | #include <glib.h> | |||
7 | #include <string.h> | |||
8 | #include <stdio.h> | |||
9 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE | |||
10 | #include "weather-priv.h" | |||
11 | ||||
12 | #ifndef BUFLEN4096 | |||
13 | #define BUFLEN4096 4096 | |||
14 | #endif /* BUFLEN */ | |||
15 | ||||
16 | int | |||
17 | main (int argc, char **argv) | |||
18 | { | |||
19 | FILE* stream = stdinstdin; | |||
20 | gchar* filename = NULL((void*)0); | |||
21 | GOptionEntry entries[] = { | |||
22 | { "file", 'f', 0, G_OPTION_ARG_FILENAME, &filename, | |||
23 | "file constaining metar observations", NULL((void*)0) }, | |||
24 | { NULL((void*)0), 0, 0, G_OPTION_ARG_NONE, NULL((void*)0), NULL((void*)0), NULL((void*)0) } | |||
25 | }; | |||
26 | GOptionContext* context; | |||
27 | GError* error = NULL((void*)0); | |||
28 | char buf[BUFLEN4096]; | |||
29 | int len; | |||
30 | WeatherInfo info; | |||
31 | ||||
32 | context = g_option_context_new ("- test libmateweather metar parser"); | |||
33 | g_option_context_add_main_entries (context, entries, NULL((void*)0)); | |||
34 | g_option_context_parse (context, &argc, &argv, &error); | |||
35 | ||||
36 | if (error) { | |||
| ||||
37 | perror (error->message); | |||
38 | return error->code; | |||
39 | } | |||
40 | if (filename) { | |||
41 | stream = fopen (filename, "r"); | |||
42 | if (!stream) { | |||
43 | perror ("fopen"); | |||
44 | return -1; | |||
45 | } | |||
46 | } else { | |||
47 | fprintf (stderrstderr, "Enter a METAR string...\n"); | |||
48 | } | |||
49 | ||||
50 | while (fgets (buf, sizeof (buf), stream)) { | |||
51 | len = strlen (buf); | |||
52 | if (buf[len - 1] == '\n') { | |||
53 | buf[--len] = '\0'; | |||
54 | } | |||
55 | printf ("\n%s\n", buf); | |||
56 | ||||
57 | memset (&info, 0, sizeof (info)); | |||
58 | info.valid = 1; | |||
59 | metar_parse (buf, &info); | |||
60 | weather_info_to_metric (&info); | |||
61 | printf ("Returned info:\n"); | |||
62 | printf (" update: %s", ctime (&info.update)); | |||
63 | printf (" sky: %s\n", weather_info_get_sky (&info)); | |||
64 | printf (" cond: %s\n", weather_info_get_conditions (&info)); | |||
65 | printf (" temp: %s\n", weather_info_get_temp (&info)); | |||
66 | printf (" dewp: %s\n", weather_info_get_dew (&info)); | |||
67 | printf (" wind: %s\n", weather_info_get_wind (&info)); | |||
68 | printf (" pressure: %s\n", weather_info_get_pressure (&info)); | |||
69 | printf (" vis: %s\n", weather_info_get_visibility (&info)); | |||
70 | ||||
71 | // TODO: retrieve location's lat/lon to display sunrise/set times | |||
72 | } | |||
73 | return 0; | |||
| ||||
74 | } |
File: | weather-metar.c |
Warning: | line 177, column 28 This statement is never executed |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | /* weather-metar.c - Weather server functions (METAR) |
3 | * |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License as |
6 | * published by the Free Software Foundation; either version 2 of the |
7 | * License, or (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, see |
16 | * <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #ifdef HAVE_CONFIG_H1 |
20 | #include <config.h> |
21 | #endif |
22 | |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <sys/types.h> |
26 | #include <regex.h> |
27 | |
28 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE |
29 | #include "weather.h" |
30 | #include "weather-priv.h" |
31 | |
32 | enum { |
33 | TIME_RE, |
34 | WIND_RE, |
35 | VIS_RE, |
36 | COND_RE, |
37 | CLOUD_RE, |
38 | TEMP_RE, |
39 | PRES_RE, |
40 | |
41 | RE_NUM |
42 | }; |
43 | |
44 | /* Return time of weather report as secs since epoch UTC */ |
45 | static time_t |
46 | make_time (gint utcDate, gint utcHour, gint utcMin) |
47 | { |
48 | const time_t now = time (NULL((void*)0)); |
49 | struct tm tm; |
50 | |
51 | localtime_r (&now, &tm); |
52 | |
53 | /* If last reading took place just before midnight UTC on the |
54 | * first, adjust the date downward to allow for the month |
55 | * change-over. This ASSUMES that the reading won't be more than |
56 | * 24 hrs old! */ |
57 | if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) { |
58 | tm.tm_mday = 0; /* mktime knows this is the last day of the previous |
59 | * month. */ |
60 | } else { |
61 | tm.tm_mday = utcDate; |
62 | } |
63 | tm.tm_hour = utcHour; |
64 | tm.tm_min = utcMin; |
65 | tm.tm_sec = 0; |
66 | |
67 | /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */ |
68 | #ifdef HAVE_TM_TM_GMOFF1 |
69 | return tm.tm_gmtoff + mktime (&tm); |
70 | #elif defined HAVE_TIMEZONE |
71 | return timezone + mktime (&tm); |
72 | #endif |
73 | } |
74 | |
75 | static void |
76 | metar_tok_time (gchar *tokp, WeatherInfo *info) |
77 | { |
78 | gint day, hr, min; |
79 | |
80 | sscanf (tokp, "%2u%2u%2u", &day, &hr, &min); |
81 | info->update = make_time (day, hr, min); |
82 | } |
83 | |
84 | static void |
85 | metar_tok_wind (gchar *tokp, WeatherInfo *info) |
86 | { |
87 | gchar sdir[4], sspd[4], sgust[4]; |
88 | gint dir, spd = -1; |
89 | gchar *gustp; |
90 | size_t glen; |
91 | |
92 | strncpy (sdir, tokp, 3); |
93 | sdir[3] = 0; |
94 | dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir); |
95 | |
96 | memset (sspd, 0, sizeof (sspd)); |
97 | glen = strspn (tokp + 3, CONST_DIGITS"0123456789"); |
98 | strncpy (sspd, tokp + 3, glen); |
99 | spd = atoi (sspd); |
100 | tokp += glen + 3; |
101 | |
102 | gustp = strchr (tokp, 'G'); |
103 | if (gustp) { |
104 | memset (sgust, 0, sizeof (sgust)); |
105 | glen = strspn (gustp + 1, CONST_DIGITS"0123456789"); |
106 | strncpy (sgust, gustp + 1, glen); |
107 | tokp = gustp + 1 + glen; |
108 | } |
109 | |
110 | if (!strcmp (tokp, "MPS")) |
111 | info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444); |
112 | else |
113 | info->windspeed = (WeatherWindSpeed)spd; |
114 | |
115 | if ((349 <= dir) || (dir <= 11)) |
116 | info->wind = WIND_N; |
117 | else if ((12 <= dir) && (dir <= 33)) |
118 | info->wind = WIND_NNE; |
119 | else if ((34 <= dir) && (dir <= 56)) |
120 | info->wind = WIND_NE; |
121 | else if ((57 <= dir) && (dir <= 78)) |
122 | info->wind = WIND_ENE; |
123 | else if ((79 <= dir) && (dir <= 101)) |
124 | info->wind = WIND_E; |
125 | else if ((102 <= dir) && (dir <= 123)) |
126 | info->wind = WIND_ESE; |
127 | else if ((124 <= dir) && (dir <= 146)) |
128 | info->wind = WIND_SE; |
129 | else if ((147 <= dir) && (dir <= 168)) |
130 | info->wind = WIND_SSE; |
131 | else if ((169 <= dir) && (dir <= 191)) |
132 | info->wind = WIND_S; |
133 | else if ((192 <= dir) && (dir <= 213)) |
134 | info->wind = WIND_SSW; |
135 | else if ((214 <= dir) && (dir <= 236)) |
136 | info->wind = WIND_SW; |
137 | else if ((237 <= dir) && (dir <= 258)) |
138 | info->wind = WIND_WSW; |
139 | else if ((259 <= dir) && (dir <= 281)) |
140 | info->wind = WIND_W; |
141 | else if ((282 <= dir) && (dir <= 303)) |
142 | info->wind = WIND_WNW; |
143 | else if ((304 <= dir) && (dir <= 326)) |
144 | info->wind = WIND_NW; |
145 | else if ((327 <= dir) && (dir <= 348)) |
146 | info->wind = WIND_NNW; |
147 | } |
148 | |
149 | static void |
150 | metar_tok_vis (gchar *tokp, WeatherInfo *info) |
151 | { |
152 | gchar *pfrac, *pend, *psp; |
153 | gchar sval[6]; |
154 | gint num, den, val; |
155 | |
156 | memset (sval, 0, sizeof (sval)); |
157 | |
158 | if (!strcmp (tokp,"CAVOK")) { |
159 | // "Ceiling And Visibility OK": visibility >= 10 KM |
160 | info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000); |
161 | info->sky = SKY_CLEAR; |
162 | } else if (0 != (pend = strstr (tokp, "SM"))) { |
163 | // US observation: field ends with "SM" |
164 | pfrac = strchr (tokp, '/'); |
165 | if (pfrac) { |
166 | if (*tokp == 'M') { |
167 | info->visibility = 0.001; |
168 | } else { |
169 | num = (*(pfrac - 1) - '0'); |
170 | strncpy (sval, pfrac + 1, pend - pfrac - 1); |
171 | den = atoi (sval); |
172 | info->visibility = |
173 | ((WeatherVisibility)num / ((WeatherVisibility)den)); |
174 | |
175 | psp = strchr (tokp, ' '); |
176 | if (psp) { |
177 | *psp = '\0'; |
This statement is never executed | |
178 | val = atoi (tokp); |
179 | info->visibility += (WeatherVisibility)val; |
180 | } |
181 | } |
182 | } else { |
183 | strncpy (sval, tokp, pend - tokp); |
184 | val = atoi (sval); |
185 | info->visibility = (WeatherVisibility)val; |
186 | } |
187 | } else { |
188 | // International observation: NNNN(DD NNNNDD)? |
189 | // For now: use only the minimum visibility and ignore its direction |
190 | strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789")); |
191 | val = atoi (sval); |
192 | info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000); |
193 | } |
194 | } |
195 | |
196 | static void |
197 | metar_tok_cloud (gchar *tokp, WeatherInfo *info) |
198 | { |
199 | gchar stype[4], salt[4]; |
200 | |
201 | strncpy (stype, tokp, 3); |
202 | stype[3] = 0; |
203 | if (strlen (tokp) == 6) { |
204 | strncpy (salt, tokp + 3, 3); |
205 | salt[3] = 0; |
206 | } |
207 | |
208 | if (!strcmp (stype, "CLR")) { |
209 | info->sky = SKY_CLEAR; |
210 | } else if (!strcmp (stype, "SKC")) { |
211 | info->sky = SKY_CLEAR; |
212 | } else if (!strcmp (stype, "NSC")) { |
213 | info->sky = SKY_CLEAR; |
214 | } else if (!strcmp (stype, "BKN")) { |
215 | info->sky = SKY_BROKEN; |
216 | } else if (!strcmp (stype, "SCT")) { |
217 | info->sky = SKY_SCATTERED; |
218 | } else if (!strcmp (stype, "FEW")) { |
219 | info->sky = SKY_FEW; |
220 | } else if (!strcmp (stype, "OVC")) { |
221 | info->sky = SKY_OVERCAST; |
222 | } |
223 | } |
224 | |
225 | static void |
226 | metar_tok_pres (gchar *tokp, WeatherInfo *info) |
227 | { |
228 | if (*tokp == 'A') { |
229 | gchar sintg[3], sfract[3]; |
230 | gint intg, fract; |
231 | |
232 | strncpy (sintg, tokp + 1, 2); |
233 | sintg[2] = 0; |
234 | intg = atoi (sintg); |
235 | |
236 | strncpy (sfract, tokp + 3, 2); |
237 | sfract[2] = 0; |
238 | fract = atoi (sfract); |
239 | |
240 | info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0); |
241 | } else { /* *tokp == 'Q' */ |
242 | gchar spres[5]; |
243 | gint pres; |
244 | |
245 | strncpy (spres, tokp + 1, 4); |
246 | spres[4] = 0; |
247 | pres = atoi (spres); |
248 | |
249 | info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373); |
250 | } |
251 | } |
252 | |
253 | static void |
254 | metar_tok_temp (gchar *tokp, WeatherInfo *info) |
255 | { |
256 | gchar *ptemp, *pdew, *psep; |
257 | |
258 | psep = strchr (tokp, '/'); |
259 | *psep = 0; |
260 | ptemp = tokp; |
261 | pdew = psep + 1; |
262 | |
263 | info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0) |
264 | : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0); |
265 | if (*pdew) { |
266 | info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0) |
267 | : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0); |
268 | } else { |
269 | info->dew = -1000.0; |
270 | } |
271 | } |
272 | |
273 | static void |
274 | metar_tok_cond (gchar *tokp, WeatherInfo *info) |
275 | { |
276 | gchar squal[3], sphen[4]; |
277 | gchar *pphen; |
278 | |
279 | if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-'))) |
280 | ++tokp; /* FIX */ |
281 | |
282 | if ((*tokp == '+') || (*tokp == '-')) |
283 | pphen = tokp + 1; |
284 | else if (strlen (tokp) < 4) |
285 | pphen = tokp; |
286 | else |
287 | pphen = tokp + 2; |
288 | |
289 | memset (squal, 0, sizeof (squal)); |
290 | strncpy (squal, tokp, pphen - tokp); |
291 | squal[pphen - tokp] = 0; |
292 | |
293 | memset (sphen, 0, sizeof (sphen)); |
294 | strncpy (sphen, pphen, sizeof (sphen)); |
295 | sphen[sizeof (sphen)-1] = '\0'; |
296 | |
297 | /* Defaults */ |
298 | info->cond.qualifier = QUALIFIER_NONE; |
299 | info->cond.phenomenon = PHENOMENON_NONE; |
300 | info->cond.significant = FALSE(0); |
301 | |
302 | if (!strcmp (squal, "")) { |
303 | info->cond.qualifier = QUALIFIER_MODERATE; |
304 | } else if (!strcmp (squal, "-")) { |
305 | info->cond.qualifier = QUALIFIER_LIGHT; |
306 | } else if (!strcmp (squal, "+")) { |
307 | info->cond.qualifier = QUALIFIER_HEAVY; |
308 | } else if (!strcmp (squal, "VC")) { |
309 | info->cond.qualifier = QUALIFIER_VICINITY; |
310 | } else if (!strcmp (squal, "MI")) { |
311 | info->cond.qualifier = QUALIFIER_SHALLOW; |
312 | } else if (!strcmp (squal, "BC")) { |
313 | info->cond.qualifier = QUALIFIER_PATCHES; |
314 | } else if (!strcmp (squal, "PR")) { |
315 | info->cond.qualifier = QUALIFIER_PARTIAL; |
316 | } else if (!strcmp (squal, "TS")) { |
317 | info->cond.qualifier = QUALIFIER_THUNDERSTORM; |
318 | } else if (!strcmp (squal, "BL")) { |
319 | info->cond.qualifier = QUALIFIER_BLOWING; |
320 | } else if (!strcmp (squal, "SH")) { |
321 | info->cond.qualifier = QUALIFIER_SHOWERS; |
322 | } else if (!strcmp (squal, "DR")) { |
323 | info->cond.qualifier = QUALIFIER_DRIFTING; |
324 | } else if (!strcmp (squal, "FZ")) { |
325 | info->cond.qualifier = QUALIFIER_FREEZING; |
326 | } else { |
327 | return; |
328 | } |
329 | |
330 | if (!strcmp (sphen, "DZ")) { |
331 | info->cond.phenomenon = PHENOMENON_DRIZZLE; |
332 | } else if (!strcmp (sphen, "RA")) { |
333 | info->cond.phenomenon = PHENOMENON_RAIN; |
334 | } else if (!strcmp (sphen, "SN")) { |
335 | info->cond.phenomenon = PHENOMENON_SNOW; |
336 | } else if (!strcmp (sphen, "SG")) { |
337 | info->cond.phenomenon = PHENOMENON_SNOW_GRAINS; |
338 | } else if (!strcmp (sphen, "IC")) { |
339 | info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS; |
340 | } else if (!strcmp (sphen, "PE")) { |
341 | info->cond.phenomenon = PHENOMENON_ICE_PELLETS; |
342 | } else if (!strcmp (sphen, "GR")) { |
343 | info->cond.phenomenon = PHENOMENON_HAIL; |
344 | } else if (!strcmp (sphen, "GS")) { |
345 | info->cond.phenomenon = PHENOMENON_SMALL_HAIL; |
346 | } else if (!strcmp (sphen, "UP")) { |
347 | info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION; |
348 | } else if (!strcmp (sphen, "BR")) { |
349 | info->cond.phenomenon = PHENOMENON_MIST; |
350 | } else if (!strcmp (sphen, "FG")) { |
351 | info->cond.phenomenon = PHENOMENON_FOG; |
352 | } else if (!strcmp (sphen, "FU")) { |
353 | info->cond.phenomenon = PHENOMENON_SMOKE; |
354 | } else if (!strcmp (sphen, "VA")) { |
355 | info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH; |
356 | } else if (!strcmp (sphen, "SA")) { |
357 | info->cond.phenomenon = PHENOMENON_SAND; |
358 | } else if (!strcmp (sphen, "HZ")) { |
359 | info->cond.phenomenon = PHENOMENON_HAZE; |
360 | } else if (!strcmp (sphen, "PY")) { |
361 | info->cond.phenomenon = PHENOMENON_SPRAY; |
362 | } else if (!strcmp (sphen, "DU")) { |
363 | info->cond.phenomenon = PHENOMENON_DUST; |
364 | } else if (!strcmp (sphen, "SQ")) { |
365 | info->cond.phenomenon = PHENOMENON_SQUALL; |
366 | } else if (!strcmp (sphen, "SS")) { |
367 | info->cond.phenomenon = PHENOMENON_SANDSTORM; |
368 | } else if (!strcmp (sphen, "DS")) { |
369 | info->cond.phenomenon = PHENOMENON_DUSTSTORM; |
370 | } else if (!strcmp (sphen, "PO")) { |
371 | info->cond.phenomenon = PHENOMENON_DUST_WHIRLS; |
372 | } else if (!strcmp (sphen, "+FC")) { |
373 | info->cond.phenomenon = PHENOMENON_TORNADO; |
374 | } else if (!strcmp (sphen, "FC")) { |
375 | info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD; |
376 | } else { |
377 | return; |
378 | } |
379 | |
380 | if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE)) |
381 | info->cond.significant = TRUE(!(0)); |
382 | } |
383 | |
384 | #define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z" |
385 | #define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" |
386 | #define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" "CAVOK" "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \ |
387 | "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \ |
388 | "CAVOK" |
389 | #define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" |
390 | #define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" |
391 | #define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" |
392 | #define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})" |
393 | |
394 | /* POSIX regular expressions do not allow us to express "match whole words |
395 | * only" in a simple way, so we have to wrap them all into |
396 | * (^| )(...regex...)( |$) |
397 | */ |
398 | #define RE_PREFIX"(^| )(" "(^| )(" |
399 | #define RE_SUFFIX")( |$)" ")( |$)" |
400 | |
401 | static regex_t metar_re[RE_NUM]; |
402 | static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info); |
403 | |
404 | static void |
405 | metar_init_re (void) |
406 | { |
407 | static gboolean initialized = FALSE(0); |
408 | if (initialized) |
409 | return; |
410 | initialized = TRUE(!(0)); |
411 | |
412 | regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1); |
413 | regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1); |
414 | regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" "CAVOK" RE_SUFFIX")( |$)", REG_EXTENDED1); |
415 | regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1); |
416 | regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1); |
417 | regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1); |
418 | regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1); |
419 | |
420 | metar_f[TIME_RE] = metar_tok_time; |
421 | metar_f[WIND_RE] = metar_tok_wind; |
422 | metar_f[VIS_RE] = metar_tok_vis; |
423 | metar_f[COND_RE] = metar_tok_cond; |
424 | metar_f[CLOUD_RE] = metar_tok_cloud; |
425 | metar_f[TEMP_RE] = metar_tok_temp; |
426 | metar_f[PRES_RE] = metar_tok_pres; |
427 | } |
428 | |
429 | gboolean |
430 | metar_parse (gchar *metar, WeatherInfo *info) |
431 | { |
432 | gchar *p; |
433 | //gchar *rmk; |
434 | gint i, i2; |
435 | regmatch_t rm, rm2; |
436 | gchar *tokp; |
437 | |
438 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
439 | g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "metar != NULL") ; return ((0)); } } while (0); |
440 | |
441 | metar_init_re (); |
442 | |
443 | /* |
444 | * Force parsing to end at "RMK" field. This prevents a subtle |
445 | * problem when info within the remark happens to match an earlier state |
446 | * and, as a result, throws off all the remaining expression |
447 | */ |
448 | if (0 != (p = strstr (metar, " RMK "))) { |
449 | *p = '\0'; |
450 | //rmk = p + 5; // uncomment this if RMK data becomes useful |
451 | } |
452 | |
453 | p = metar; |
454 | i = TIME_RE; |
455 | while (*p) { |
456 | |
457 | i2 = RE_NUM; |
458 | rm2.rm_so = strlen (p); |
459 | rm2.rm_eo = rm2.rm_so; |
460 | |
461 | for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) { |
462 | if (0 == regexec (&metar_re[i], p, 1, &rm, 0) |
463 | && rm.rm_so < rm2.rm_so) |
464 | { |
465 | i2 = i; |
466 | /* Skip leading and trailing space characters, if present. |
467 | (the regular expressions include those characters to |
468 | only get matches limited to whole words). */ |
469 | if (p[rm.rm_so] == ' ') rm.rm_so++; |
470 | if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--; |
471 | rm2.rm_so = rm.rm_so; |
472 | rm2.rm_eo = rm.rm_eo; |
473 | } |
474 | } |
475 | |
476 | if (i2 != RE_NUM) { |
477 | tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so); |
478 | metar_f[i2] (tokp, info); |
479 | g_free (tokp); |
480 | } |
481 | |
482 | p += rm2.rm_eo; |
483 | p += strspn (p, " "); |
484 | } |
485 | return TRUE(!(0)); |
486 | } |
487 | |
488 | static void |
489 | metar_finish (SoupSession *session, SoupMessage *msg, gpointer data) |
490 | { |
491 | WeatherInfo *info = (WeatherInfo *)data; |
492 | WeatherLocation *loc; |
493 | const gchar *p, *endtag; |
494 | gchar *searchkey, *metar; |
495 | gboolean success = FALSE(0); |
496 | |
497 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
498 | |
499 | if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code ) < 300)) { |
500 | if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code ) < 100)) |
501 | info->network_error = TRUE(!(0)); |
502 | else { |
503 | /* Translators: %d is an error code, and %s the error string */ |
504 | g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")), |
505 | msg->status_code, msg->reason_phrase); |
506 | } |
507 | request_done (info, FALSE(0)); |
508 | return; |
509 | } |
510 | |
511 | loc = info->location; |
512 | |
513 | searchkey = g_strdup_printf ("<raw_text>%s", loc->code); |
514 | p = strstr (msg->response_body->data, searchkey); |
515 | g_free (searchkey); |
516 | if (p) { |
517 | p += WEATHER_LOCATION_CODE_LEN4 + 11; |
518 | endtag = strstr (p, "</raw_text>"); |
519 | if (endtag) |
520 | metar = g_strndup (p, endtag - p); |
521 | else |
522 | metar = g_strdup (p); |
523 | success = metar_parse (metar, info); |
524 | g_free (metar); |
525 | } else if (!strstr (msg->response_body->data, "aviationweather.gov")) { |
526 | /* The response doesn't even seem to have come from NOAA... |
527 | * most likely it is a wifi hotspot login page. Call that a |
528 | * network error. |
529 | */ |
530 | info->network_error = TRUE(!(0)); |
531 | } |
532 | |
533 | info->valid = success; |
534 | request_done (info, TRUE(!(0))); |
535 | } |
536 | |
537 | /* Read current conditions and fill in info structure */ |
538 | void |
539 | metar_start_open (WeatherInfo *info) |
540 | { |
541 | WeatherLocation *loc; |
542 | SoupMessage *msg; |
543 | |
544 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
545 | info->valid = info->network_error = FALSE(0); |
546 | loc = info->location; |
547 | if (loc == NULL((void*)0)) { |
548 | g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location"))); |
549 | return; |
550 | } |
551 | |
552 | msg = soup_form_request_new ( |
553 | "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam", |
554 | "dataSource", "metars", |
555 | "requestType", "retrieve", |
556 | "format", "xml", |
557 | "hoursBeforeNow", "3", |
558 | "mostRecent", "true", |
559 | "fields", "raw_text", |
560 | "stationString", loc->code, |
561 | NULL((void*)0)); |
562 | soup_session_queue_message (info->session, msg, metar_finish, info); |
563 | |
564 | info->requests_pending++; |
565 | } |
File: | weather-sun.c |
Warning: | line 335, column 12 This statement is never executed |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | /* weather-sun.c - Astronomy calculations for mateweather |
3 | * |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License as |
6 | * published by the Free Software Foundation; either version 2 of the |
7 | * License, or (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, see |
16 | * <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | /* |
20 | * Formulas from: |
21 | * "Practical Astronomy With Your Calculator" (3e), Peter Duffett-Smith |
22 | * Cambridge University Press 1988 |
23 | * Unless otherwise noted, comments referencing "steps" are related to |
24 | * the algorithm presented in section 49 of above |
25 | */ |
26 | |
27 | #ifdef HAVE_CONFIG_H1 |
28 | #include <config.h> |
29 | #endif |
30 | |
31 | #include <math.h> |
32 | #include <time.h> |
33 | #include <glib.h> |
34 | |
35 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE |
36 | #include "weather-priv.h" |
37 | |
38 | #define ECCENTRICITY(d)(0.01671123 - (d)/36525.*0.00004392) (0.01671123 - (d)/36525.*0.00004392) |
39 | |
40 | /* |
41 | * Ecliptic longitude of the sun at specified time (UT) |
42 | * The algoithm is described in section 47 of Duffett-Smith |
43 | * Return value is in radians |
44 | */ |
45 | gdouble |
46 | sunEclipLongitude(time_t t) |
47 | { |
48 | gdouble ndays, meanAnom, eccenAnom, delta, e, longitude; |
49 | |
50 | /* |
51 | * Start with an estimate based on a fixed daily rate |
52 | */ |
53 | ndays = EPOCH_TO_J2000(t)((gdouble)(t)-946727935.816) / 86400.; |
54 | meanAnom = DEGREES_TO_RADIANS(MEAN_ECLIPTIC_LONGITUDE(ndays)((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846 ) |
55 | - PERIGEE_LONGITUDE(ndays))((fmod (((280.46457166 + (ndays)/36525.*35999.37244981) - (282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180.) * 3.14159265358979323846 ); |
56 | |
57 | /* |
58 | * Approximate solution of Kepler's equation: |
59 | * Find E which satisfies E - e sin(E) = M (mean anomaly) |
60 | */ |
61 | eccenAnom = meanAnom; |
62 | e = ECCENTRICITY(ndays)(0.01671123 - (ndays)/36525.*0.00004392); |
63 | |
64 | while (1e-12 < fabs( delta = eccenAnom - e * sin(eccenAnom) - meanAnom)) |
65 | { |
66 | eccenAnom -= delta / (1.- e * cos(eccenAnom)); |
67 | } |
68 | |
69 | /* |
70 | * Earth's longitude on the ecliptic |
71 | */ |
72 | longitude = fmod( DEGREES_TO_RADIANS (PERIGEE_LONGITUDE(ndays))((fmod (((282.93768193 + (ndays)/36525.*0.32327364)),360.) / 180. ) * 3.14159265358979323846) |
73 | + 2. * atan (sqrt ((1.+e)/(1.-e)) |
74 | * tan (eccenAnom / 2.)), |
75 | 2. * M_PI3.14159265358979323846); |
76 | if (longitude < 0.) { |
77 | longitude += 2 * M_PI3.14159265358979323846; |
78 | } |
79 | return longitude; |
80 | } |
81 | |
82 | static gdouble |
83 | ecliptic_obliquity (gdouble time) |
84 | { |
85 | gdouble jc = EPOCH_TO_J2000 (time)((gdouble)(time)-946727935.816) / (36525. * 86400.); |
86 | gdouble eclip_secs = (84381.448 |
87 | - (46.84024 * jc) |
88 | - (59.e-5 * jc * jc) |
89 | + (1.813e-3 * jc * jc * jc)); |
90 | return DEGREES_TO_RADIANS(eclip_secs / 3600.)((fmod ((eclip_secs / 3600.),360.) / 180.) * 3.14159265358979323846 ); |
91 | } |
92 | |
93 | /* |
94 | * Convert ecliptic longitude and latitude (radians) to equitorial |
95 | * coordinates, expressed as right ascension (hours) and |
96 | * declination (radians) |
97 | */ |
98 | void |
99 | ecl2equ (gdouble time, |
100 | gdouble eclipLon, gdouble eclipLat, |
101 | gdouble *ra, gdouble *decl) |
102 | { |
103 | gdouble mEclipObliq = ecliptic_obliquity(time); |
104 | |
105 | if (ra) { |
106 | *ra = RADIANS_TO_HOURS (atan2 ((sin (eclipLon) * cos (mEclipObliq)((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat) * sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846 ) |
107 | - tan (eclipLat) * sin(mEclipObliq)),((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat) * sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846 ) |
108 | cos (eclipLon)))((atan2 ((sin (eclipLon) * cos (mEclipObliq) - tan (eclipLat) * sin(mEclipObliq)), cos (eclipLon))) * 12. / 3.14159265358979323846 ); |
109 | if (*ra < 0.) |
110 | *ra += 24.; |
111 | } |
112 | if (decl) { |
113 | *decl = asin (( sin (eclipLat) * cos (mEclipObliq)) |
114 | + cos (eclipLat) * sin (mEclipObliq) * sin(eclipLon)); |
115 | } |
116 | } |
117 | |
118 | /* |
119 | * Calculate rising and setting times for an object |
120 | * based on it equitorial coordinates (section 33 & 15) |
121 | * Returned "rise" and "set" values are sideral times in hours |
122 | */ |
123 | static void |
124 | gstObsv (gdouble ra, gdouble decl, |
125 | gdouble obsLat, gdouble obsLon, |
126 | gdouble *rise, gdouble *set) |
127 | { |
128 | double a = acos (-tan (obsLat) * tan (decl)); |
129 | double b; |
130 | |
131 | if (isnan (a)__builtin_isnan (a) != 0) { |
132 | *set = *rise = a; |
133 | return; |
134 | } |
135 | a = RADIANS_TO_HOURS (a)((a) * 12. / 3.14159265358979323846); |
136 | b = 24. - a + ra; |
137 | a += ra; |
138 | a -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846); |
139 | b -= RADIANS_TO_HOURS (obsLon)((obsLon) * 12. / 3.14159265358979323846); |
140 | if ((a = fmod (a, 24.)) < 0) |
141 | a += 24.; |
142 | if ((b = fmod (b, 24.)) < 0) |
143 | b += 24.; |
144 | |
145 | *set = a; |
146 | *rise = b; |
147 | } |
148 | |
149 | static gdouble |
150 | t0 (time_t date) |
151 | { |
152 | gdouble t = ((gdouble)(EPOCH_TO_J2000 (date)((gdouble)(date)-946727935.816) / 86400)) / 36525.0; |
153 | gdouble t0 = fmod (6.697374558 + 2400.051366 * t + 2.5862e-5 * t * t, 24.); |
154 | if (t0 < 0.) |
155 | t0 += 24.; |
156 | return t0; |
157 | } |
158 | |
159 | static gboolean |
160 | calc_sun2 (WeatherInfo *info, time_t t) |
161 | { |
162 | gdouble obsLat = info->location->latitude; |
163 | gdouble obsLon = info->location->longitude; |
164 | time_t gm_midn; |
165 | time_t lcl_midn; |
166 | gdouble gm_hoff, lambda; |
167 | gdouble ra1, ra2; |
168 | gdouble decl1, decl2; |
169 | gdouble decl_midn, decl_noon; |
170 | gdouble rise1, rise2; |
171 | gdouble set1, set2; |
172 | gdouble tt, t00; |
173 | gdouble x, u, dt; |
174 | |
175 | /* Approximate preceding local midnight at observer's longitude */ |
176 | obsLat = info->location->latitude; |
177 | obsLon = info->location->longitude; |
178 | gm_midn = t - (t % 86400); |
179 | gm_hoff = floor ((RADIANS_TO_DEGREES (obsLon)((obsLon) * 180. / 3.14159265358979323846) + 7.5) / 15.); |
180 | lcl_midn = gm_midn - 3600. * gm_hoff; |
181 | if (t - lcl_midn >= 86400) |
182 | lcl_midn += 86400; |
183 | else if (lcl_midn > t) |
184 | lcl_midn -= 86400; |
185 | |
186 | lambda = sunEclipLongitude (lcl_midn); |
187 | |
188 | /* |
189 | * Calculate equitorial coordinates of sun at previous |
190 | * and next local midnights |
191 | */ |
192 | ecl2equ (lcl_midn, lambda, 0., &ra1, &decl1); |
193 | ecl2equ (lcl_midn + 86400., |
194 | lambda + DEGREES_TO_RADIANS(SOL_PROGRESSION)((fmod (((360./365.242191)),360.) / 180.) * 3.14159265358979323846 ), 0., |
195 | &ra2, &decl2); |
196 | |
197 | /* |
198 | * If the observer is within the Arctic or Antarctic Circles then |
199 | * the sun may be above or below the horizon for the full day. |
200 | */ |
201 | decl_midn = MIN(decl1,decl2)(((decl1) < (decl2)) ? (decl1) : (decl2)); |
202 | decl_noon = (decl1+decl2)/2.; |
203 | info->midnightSun = |
204 | (obsLat > (M_PI3.14159265358979323846/2.-decl_midn)) || (obsLat < (-M_PI3.14159265358979323846/2.-decl_midn)); |
205 | info->polarNight = |
206 | (obsLat > (M_PI3.14159265358979323846/2.+decl_noon)) || (obsLat < (-M_PI3.14159265358979323846/2.+decl_noon)); |
207 | if (info->midnightSun || info->polarNight) { |
208 | info->sunriseValid = info->sunsetValid = FALSE(0); |
209 | return FALSE(0); |
210 | } |
211 | |
212 | /* |
213 | * Convert to rise and set times based positions for the preceding |
214 | * and following local midnights. |
215 | */ |
216 | gstObsv (ra1, decl1, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise1, &set1); |
217 | gstObsv (ra2, decl2, obsLat, obsLon - (gm_hoff * M_PI3.14159265358979323846 / 12.), &rise2, &set2); |
218 | |
219 | /* TODO: include calculations for regions near the poles. */ |
220 | if (isnan(rise1)__builtin_isnan (rise1) || isnan(rise2)__builtin_isnan (rise2)) { |
221 | info->sunriseValid = info->sunsetValid = FALSE(0); |
222 | return FALSE(0); |
223 | } |
224 | |
225 | if (rise2 < rise1) { |
226 | rise2 += 24.; |
227 | } |
228 | if (set2 < set1) { |
229 | set2 += 24.; |
230 | } |
231 | |
232 | tt = t0(lcl_midn); |
233 | t00 = tt - (gm_hoff + RADIANS_TO_HOURS(obsLon)((obsLon) * 12. / 3.14159265358979323846)) * 1.002737909; |
234 | |
235 | if (t00 < 0.) |
236 | t00 += 24.; |
237 | |
238 | if (rise1 < t00) { |
239 | rise1 += 24.; |
240 | rise2 += 24.; |
241 | } |
242 | if (set1 < t00) { |
243 | set1 += 24.; |
244 | set2 += 24.; |
245 | } |
246 | |
247 | /* |
248 | * Interpolate between the two to get a rise and set time |
249 | * based on the sun's position at local noon (step 8) |
250 | */ |
251 | rise1 = (24.07 * rise1 - t00 * (rise2 - rise1)) / (24.07 + rise1 - rise2); |
252 | set1 = (24.07 * set1 - t00 * (set2 - set1)) / (24.07 + set1 - set2); |
253 | |
254 | /* |
255 | * Calculate an adjustment value to account for parallax, |
256 | * refraction and the Sun's finite diameter (steps 9,10) |
257 | */ |
258 | decl2 = (decl1 + decl2) / 2.; |
259 | x = DEGREES_TO_RADIANS(0.830725)((fmod ((0.830725),360.) / 180.) * 3.14159265358979323846); |
260 | u = acos ( sin(obsLat) / cos(decl2) ); |
261 | dt = RADIANS_TO_HOURS ( asin ( sin(x) / sin(u) ) / cos(decl2) )((asin ( sin(x) / sin(u) ) / cos(decl2)) * 12. / 3.14159265358979323846 ); |
262 | |
263 | /* |
264 | * Subtract the correction value from sunrise and add to sunset, |
265 | * then (step 11) convert sideral times to UT |
266 | */ |
267 | rise1 = (rise1 - dt - tt) * 0.9972695661; |
268 | if (rise1 < 0.) |
269 | rise1 += 24; |
270 | else if (rise1 >= 24.) |
271 | rise1 -= 24.; |
272 | info->sunriseValid = ((rise1 >= 0.) && (rise1 < 24.)); |
273 | info->sunrise = (rise1 * 3600.) + lcl_midn; |
274 | |
275 | set1 = (set1 + dt - tt) * 0.9972695661; |
276 | if (set1 < 0.) |
277 | set1 += 24; |
278 | else if (set1 >= 24.) |
279 | set1 -= 24.; |
280 | info->sunsetValid = ((set1 >= 0.) && (set1 < 24.)); |
281 | info->sunset = (set1 * 3600.) + lcl_midn; |
282 | |
283 | return (info->sunriseValid || info->sunsetValid); |
284 | } |
285 | |
286 | /** |
287 | * calc_sun_time: |
288 | * @info: #WeatherInfo structure containing the observer's latitude |
289 | * and longitude in radians, fills in the sunrise and sunset times. |
290 | * @t: time_t |
291 | * |
292 | * Returns: gboolean indicating if the results are valid. |
293 | */ |
294 | gboolean |
295 | calc_sun_time (WeatherInfo *info, time_t t) |
296 | { |
297 | return info->location->latlon_valid && calc_sun2 (info, t); |
298 | } |
299 | |
300 | /** |
301 | * calc_sun: |
302 | * @info: #WeatherInfo structure containing the observer's latitude |
303 | * and longitude in radians, fills in the sunrise and sunset times. |
304 | * |
305 | * Returns: gboolean indicating if the results are valid. |
306 | */ |
307 | gboolean |
308 | calc_sun (WeatherInfo *info) |
309 | { |
310 | return calc_sun_time(info, time(NULL((void*)0))); |
311 | } |
312 | |
313 | /** |
314 | * weather_info_next_sun_event: |
315 | * @info: #WeatherInfo structure |
316 | * |
317 | * Returns: the interval, in seconds, until the next "sun event": |
318 | * - local midnight, when rise and set times are recomputed |
319 | * - next sunrise, when icon changes to daytime version |
320 | * - next sunset, when icon changes to nighttime version |
321 | */ |
322 | gint |
323 | weather_info_next_sun_event (WeatherInfo *info) |
324 | { |
325 | time_t now = time (NULL((void*)0)); |
326 | struct tm ltm; |
327 | time_t nxtEvent; |
328 | |
329 | g_return_val_if_fail (info != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (-1); } } while (0); |
330 | |
331 | if (!calc_sun (info)) |
332 | return -1; |
333 | |
334 | /* Determine when the next local midnight occurs */ |
335 | (void) localtime_r (&now, <m); |
This statement is never executed | |
336 | ltm.tm_sec = 0; |
337 | ltm.tm_min = 0; |
338 | ltm.tm_hour = 0; |
339 | ltm.tm_mday++; |
340 | nxtEvent = mktime (<m); |
341 | |
342 | if (info->sunsetValid && |
343 | (info->sunset > now) && (info->sunset < nxtEvent)) |
344 | nxtEvent = info->sunset; |
345 | if (info->sunriseValid && |
346 | (info->sunrise > now) && (info->sunrise < nxtEvent)) |
347 | nxtEvent = info->sunrise; |
348 | return (gint)(nxtEvent - now); |
349 | } |
File: | weather.c |
Warning: | line 495, column 9 Value stored to 'location' is never read |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | /* weather.c - Overall weather server functions |
3 | * |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License as |
6 | * published by the Free Software Foundation; either version 2 of the |
7 | * License, or (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, see |
16 | * <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #ifdef HAVE_CONFIG_H1 |
20 | #include <config.h> |
21 | #endif |
22 | |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <assert.h> |
26 | #include <string.h> |
27 | #include <ctype.h> |
28 | #include <math.h> |
29 | #include <fenv.h> |
30 | |
31 | #ifdef HAVE_VALUES_H |
32 | #include <values.h> |
33 | #endif |
34 | |
35 | #include <time.h> |
36 | #include <unistd.h> |
37 | |
38 | #include <gdk-pixbuf/gdk-pixbuf.h> |
39 | |
40 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE |
41 | #include "weather.h" |
42 | #include "weather-priv.h" |
43 | |
44 | #define MOON_PHASES36 36 |
45 | |
46 | /** |
47 | * SECTION:weather |
48 | * @Title: weather |
49 | */ |
50 | |
51 | static void _weather_internal_check (void); |
52 | |
53 | static inline void |
54 | mateweather_gettext_init (void) |
55 | { |
56 | static gsize mateweather_gettext_initialized = FALSE(0); |
57 | |
58 | if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if ( (__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized ) == sizeof (gpointer), "Expression evaluates to false"); (void ) (0 ? (gpointer) *(&mateweather_gettext_initialized) : ( (void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(& mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false" ); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval ; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic = (&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic , &gapg_temp_newval, 5); gapg_temp_newval; })) && g_once_init_enter (&mateweather_gettext_initialized)); } ))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 0))) { |
59 | bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale"); |
60 | #ifdef HAVE_BIND_TEXTDOMAIN_CODESET |
61 | bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8"); |
62 | #endif |
63 | g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized ) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void) (*(&mateweather_gettext_initialized) = ((!(0)))) : (void) 0; g_once_init_leave ((&mateweather_gettext_initialized ), (gsize) ((!(0)))); })); |
64 | } |
65 | } |
66 | |
67 | const char * |
68 | mateweather_gettext (const char *str) |
69 | { |
70 | mateweather_gettext_init (); |
71 | return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5); |
72 | } |
73 | |
74 | const char * |
75 | mateweather_dpgettext (const char *context, |
76 | const char *str) |
77 | { |
78 | mateweather_gettext_init (); |
79 | return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str); |
80 | } |
81 | |
82 | /* |
83 | * Convert string of the form "DD-MM-SSH" to radians |
84 | * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW) |
85 | * Return value is positive for N,E; negative for S,W. |
86 | */ |
87 | static gdouble |
88 | dmsh2rad (const gchar *latlon) |
89 | { |
90 | char *p1, *p2; |
91 | int deg, min, sec, dir; |
92 | gdouble value; |
93 | |
94 | if (latlon == NULL((void*)0)) |
95 | return DBL_MAX1.7976931348623157e+308; |
96 | p1 = strchr (latlon, '-'); |
97 | p2 = strrchr (latlon, '-'); |
98 | if (p1 == NULL((void*)0) || p1 == latlon) { |
99 | return DBL_MAX1.7976931348623157e+308; |
100 | } else if (p1 == p2) { |
101 | sscanf (latlon, "%d-%d", °, &min); |
102 | sec = 0; |
103 | } else if (p2 == 1 + p1) { |
104 | return DBL_MAX1.7976931348623157e+308; |
105 | } else { |
106 | sscanf (latlon, "%d-%d-%d", °, &min, &sec); |
107 | } |
108 | if (deg > 180 || min >= 60 || sec >= 60) |
109 | return DBL_MAX1.7976931348623157e+308; |
110 | value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.; |
111 | |
112 | dir = g_ascii_toupper (latlon[strlen (latlon) - 1]); |
113 | if (dir == 'W' || dir == 'S') |
114 | value = -value; |
115 | else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0')) |
116 | value = DBL_MAX1.7976931348623157e+308; |
117 | return value; |
118 | } |
119 | |
120 | WeatherLocation * |
121 | weather_location_new (const gchar *name, const gchar *code, |
122 | const gchar *zone, const gchar *radar, |
123 | const gchar *coordinates, |
124 | const gchar *country_code, |
125 | const gchar *tz_hint) |
126 | { |
127 | WeatherLocation *location; |
128 | |
129 | _weather_internal_check (); |
130 | |
131 | location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1) ; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s == 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n ) && (__s == 0 || __n <= (9223372036854775807L *2UL +1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s); __p; })); |
132 | |
133 | /* name and metar code must be set */ |
134 | location->name = g_strdup (name); |
135 | location->code = g_strdup (code); |
136 | |
137 | if (zone) { |
138 | location->zone = g_strdup (zone); |
139 | } else { |
140 | location->zone = g_strdup ("------"); |
141 | } |
142 | |
143 | if (radar) { |
144 | location->radar = g_strdup (radar); |
145 | } else { |
146 | location->radar = g_strdup ("---"); |
147 | } |
148 | |
149 | if (location->zone[0] == '-') { |
150 | location->zone_valid = FALSE(0); |
151 | } else { |
152 | location->zone_valid = TRUE(!(0)); |
153 | } |
154 | |
155 | location->coordinates = NULL((void*)0); |
156 | if (coordinates) |
157 | { |
158 | char **pieces; |
159 | |
160 | pieces = g_strsplit (coordinates, " ", -1); |
161 | |
162 | if (g_strv_length (pieces) == 2) |
163 | { |
164 | location->coordinates = g_strdup (coordinates); |
165 | location->latitude = dmsh2rad (pieces[0]); |
166 | location->longitude = dmsh2rad (pieces[1]); |
167 | } |
168 | |
169 | g_strfreev (pieces); |
170 | } |
171 | |
172 | if (!location->coordinates) |
173 | { |
174 | location->coordinates = g_strdup ("---"); |
175 | location->latitude = DBL_MAX1.7976931348623157e+308; |
176 | location->longitude = DBL_MAX1.7976931348623157e+308; |
177 | } |
178 | |
179 | location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308); |
180 | |
181 | location->country_code = g_strdup (country_code); |
182 | location->tz_hint = g_strdup (tz_hint); |
183 | |
184 | return location; |
185 | } |
186 | |
187 | WeatherLocation * |
188 | weather_location_clone (const WeatherLocation *location) |
189 | { |
190 | WeatherLocation *clone; |
191 | |
192 | g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "location != NULL" ); return (((void*)0)); } } while (0); |
193 | |
194 | clone = weather_location_new (location->name, |
195 | location->code, location->zone, |
196 | location->radar, location->coordinates, |
197 | location->country_code, location->tz_hint); |
198 | clone->latitude = location->latitude; |
199 | clone->longitude = location->longitude; |
200 | clone->latlon_valid = location->latlon_valid; |
201 | return clone; |
202 | } |
203 | |
204 | void |
205 | weather_location_free (WeatherLocation *location) |
206 | { |
207 | if (location) { |
208 | g_free (location->name); |
209 | g_free (location->code); |
210 | g_free (location->zone); |
211 | g_free (location->radar); |
212 | g_free (location->coordinates); |
213 | g_free (location->country_code); |
214 | g_free (location->tz_hint); |
215 | |
216 | g_free (location); |
217 | } |
218 | } |
219 | |
220 | gboolean |
221 | weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2) |
222 | { |
223 | /* if something is NULL, then it's TRUE if and only if both are NULL) */ |
224 | if (location1 == NULL((void*)0) || location2 == NULL((void*)0)) |
225 | return (location1 == location2); |
226 | if (!location1->code || !location2->code) |
227 | return (location1->code == location2->code); |
228 | if (!location1->name || !location2->name) |
229 | return (location1->name == location2->name); |
230 | |
231 | return ((strcmp (location1->code, location2->code) == 0) && |
232 | (strcmp (location1->name, location2->name) == 0)); |
233 | } |
234 | |
235 | static const gchar *wind_direction_str[] = { |
236 | N_("Variable")("Variable"), |
237 | N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"), |
238 | N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"), |
239 | N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"), |
240 | N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest") |
241 | }; |
242 | |
243 | const gchar * |
244 | weather_wind_direction_string (WeatherWindDirection wind) |
245 | { |
246 | if (wind <= WIND_INVALID || wind >= WIND_LAST) |
247 | return _("Invalid")(mateweather_gettext ("Invalid")); |
248 | |
249 | return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind])); |
250 | } |
251 | |
252 | static const gchar *sky_str[] = { |
253 | N_("Clear Sky")("Clear Sky"), |
254 | N_("Broken clouds")("Broken clouds"), |
255 | N_("Scattered clouds")("Scattered clouds"), |
256 | N_("Few clouds")("Few clouds"), |
257 | N_("Overcast")("Overcast") |
258 | }; |
259 | |
260 | const gchar * |
261 | weather_sky_string (WeatherSky sky) |
262 | { |
263 | if (sky <= SKY_INVALID || sky >= SKY_LAST) |
264 | return _("Invalid")(mateweather_gettext ("Invalid")); |
265 | |
266 | return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky])); |
267 | } |
268 | |
269 | /* |
270 | * Even though tedious, I switched to a 2D array for weather condition |
271 | * strings, in order to facilitate internationalization, esp. for languages |
272 | * with genders. |
273 | */ |
274 | |
275 | /* |
276 | * Almost all reportable combinations listed in |
277 | * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those |
278 | * having 2 qualifiers mixed together [such as "Blowing snow in vicinity" |
279 | * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc]. |
280 | * Combinations that are not possible are filled in with "??". |
281 | * Some other exceptions not handled yet, such as "SN BLSN" which has |
282 | * special meaning. |
283 | */ |
284 | |
285 | /* |
286 | * Note, magic numbers, when you change the size here, make sure to change |
287 | * the below function so that new values are recognized |
288 | */ |
289 | /* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */ |
290 | /* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ |
291 | static const gchar *conditions_str[24][13] = { |
292 | /* Translators: If you want to know what "blowing" "shallow" "partial" |
293 | * etc means, you can go to http://www.weather.com/glossary/ and |
294 | * http://www.crh.noaa.gov/arx/wx.tbl.php */ |
295 | /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" }, |
296 | /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") }, |
297 | /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") }, |
298 | /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" }, |
299 | /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" }, |
300 | /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
301 | /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" }, |
302 | /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", }, |
303 | /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" }, |
304 | /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
305 | /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
306 | /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") }, |
307 | /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
308 | /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
309 | /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" }, |
310 | /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
311 | /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" }, |
312 | /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" }, |
313 | /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
314 | /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" }, |
315 | /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" }, |
316 | /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
317 | /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
318 | /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" } |
319 | }; |
320 | |
321 | const gchar * |
322 | weather_conditions_string (WeatherConditions cond) |
323 | { |
324 | const gchar *str; |
325 | |
326 | if (!cond.significant) { |
327 | return "-"; |
328 | } else { |
329 | if (cond.phenomenon > PHENOMENON_INVALID && |
330 | cond.phenomenon < PHENOMENON_LAST && |
331 | cond.qualifier > QUALIFIER_INVALID && |
332 | cond.qualifier < QUALIFIER_LAST) |
333 | str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int )cond.qualifier])); |
334 | else |
335 | str = _("Invalid")(mateweather_gettext ("Invalid")); |
336 | return (strlen (str) > 0) ? str : "-"; |
337 | } |
338 | } |
339 | |
340 | /* Locals turned global to facilitate asynchronous HTTP requests */ |
341 | |
342 | gboolean |
343 | requests_init (WeatherInfo *info) |
344 | { |
345 | if (info->requests_pending) |
346 | return FALSE(0); |
347 | |
348 | return TRUE(!(0)); |
349 | } |
350 | |
351 | void request_done (WeatherInfo *info, gboolean ok) |
352 | { |
353 | if (ok) { |
354 | (void) calc_sun (info); |
355 | info->moonValid = info->valid && calc_moon (info); |
356 | } |
357 | if (!--info->requests_pending) |
358 | info->finish_cb (info, info->cb_data); |
359 | } |
360 | |
361 | /* it's OK to pass in NULL */ |
362 | void |
363 | free_forecast_list (WeatherInfo *info) |
364 | { |
365 | GSList *p; |
366 | |
367 | if (!info) |
368 | return; |
369 | |
370 | for (p = info->forecast_list; p; p = p->next) |
371 | weather_info_free (p->data); |
372 | |
373 | if (info->forecast_list) { |
374 | g_slist_free (info->forecast_list); |
375 | info->forecast_list = NULL((void*)0); |
376 | } |
377 | } |
378 | |
379 | /* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */ |
380 | |
381 | static inline gdouble |
382 | calc_humidity (gdouble temp, gdouble dewp) |
383 | { |
384 | gdouble esat, esurf; |
385 | |
386 | if (temp > -500.0 && dewp > -500.0) { |
387 | temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)); |
388 | dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0)); |
389 | |
390 | esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp)); |
391 | esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp)); |
392 | } else { |
393 | esurf = -1.0; |
394 | esat = 1.0; |
395 | } |
396 | return ((esurf/esat) * 100.0); |
397 | } |
398 | |
399 | static inline gdouble |
400 | calc_apparent (WeatherInfo *info) |
401 | { |
402 | gdouble temp = info->temp; |
403 | gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779); |
404 | gdouble apparent = -1000.; |
405 | |
406 | /* |
407 | * Wind chill calculations as of 01-Nov-2001 |
408 | * http://www.nws.noaa.gov/om/windchill/index.shtml |
409 | * Some pages suggest that the formula will soon be adjusted |
410 | * to account for solar radiation (bright sun vs cloudy sky) |
411 | */ |
412 | if (temp <= 50.0) { |
413 | if (wind > 3.0) { |
414 | gdouble v = pow (wind, 0.16); |
415 | apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v; |
416 | } else if (wind >= 0.) { |
417 | apparent = temp; |
418 | } |
419 | } |
420 | /* |
421 | * Heat index calculations: |
422 | * http://www.srh.noaa.gov/fwd/heatindex/heat5.html |
423 | */ |
424 | else if (temp >= 80.0) { |
425 | if (info->temp >= -500. && info->dew >= -500.) { |
426 | gdouble humidity = calc_humidity (info->temp, info->dew); |
427 | gdouble t2 = temp * temp; |
428 | gdouble h2 = humidity * humidity; |
429 | |
430 | #if 1 |
431 | /* |
432 | * A really precise formula. Note that overall precision is |
433 | * constrained by the accuracy of the instruments and that the |
434 | * we receive the temperature and dewpoints as integers. |
435 | */ |
436 | gdouble t3 = t2 * temp; |
437 | gdouble h3 = h2 * temp; |
438 | |
439 | apparent = 16.923 |
440 | + 0.185212 * temp |
441 | + 5.37941 * humidity |
442 | - 0.100254 * temp * humidity |
443 | + 9.41695e-3 * t2 |
444 | + 7.28898e-3 * h2 |
445 | + 3.45372e-4 * t2 * humidity |
446 | - 8.14971e-4 * temp * h2 |
447 | + 1.02102e-5 * t2 * h2 |
448 | - 3.8646e-5 * t3 |
449 | + 2.91583e-5 * h3 |
450 | + 1.42721e-6 * t3 * humidity |
451 | + 1.97483e-7 * temp * h3 |
452 | - 2.18429e-8 * t3 * h2 |
453 | + 8.43296e-10 * t2 * h3 |
454 | - 4.81975e-11 * t3 * h3; |
455 | #else |
456 | /* |
457 | * An often cited alternative: values are within 5 degrees for |
458 | * most ranges between 10% and 70% humidity and to 110 degrees. |
459 | */ |
460 | apparent = - 42.379 |
461 | + 2.04901523 * temp |
462 | + 10.14333127 * humidity |
463 | - 0.22475541 * temp * humidity |
464 | - 6.83783e-3 * t2 |
465 | - 5.481717e-2 * h2 |
466 | + 1.22874e-3 * t2 * humidity |
467 | + 8.5282e-4 * temp * h2 |
468 | - 1.99e-6 * t2 * h2; |
469 | #endif |
470 | } |
471 | } else { |
472 | apparent = temp; |
473 | } |
474 | |
475 | return apparent; |
476 | } |
477 | |
478 | WeatherInfo * |
479 | _weather_info_fill (WeatherInfo *info, |
480 | WeatherLocation *location, |
481 | const WeatherPrefs *prefs, |
482 | WeatherInfoFunc cb, |
483 | gpointer data) |
484 | { |
485 | g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (((info == ((void*)0)) && (location != ((void*)0 ))) || ((info != ((void*)0)) && (location == ((void*) 0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 1))) { } else { g_return_if_fail_warning ("MateWeather" , ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))" ); return (((void*)0)); } } while (0) |
486 | ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (((info == ((void*)0)) && (location != ((void*)0 ))) || ((info != ((void*)0)) && (location == ((void*) 0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 1))) { } else { g_return_if_fail_warning ("MateWeather" , ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))" ); return (((void*)0)); } } while (0); |
487 | g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "prefs != NULL") ; return (((void*)0)); } } while (0); |
488 | |
489 | /* FIXME: i'm not sure this works as intended anymore */ |
490 | if (!info) { |
491 | info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize __s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p = g_malloc0 (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s )) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s ); __p; })); |
492 | info->requests_pending = 0; |
493 | info->location = weather_location_clone (location); |
494 | } else { |
495 | location = info->location; |
Value stored to 'location' is never read | |
496 | if (info->forecast) |
497 | g_free (info->forecast); |
498 | info->forecast = NULL((void*)0); |
499 | |
500 | free_forecast_list (info); |
501 | |
502 | if (info->radar != NULL((void*)0)) { |
503 | g_object_unref (info->radar); |
504 | info->radar = NULL((void*)0); |
505 | } |
506 | } |
507 | |
508 | /* Update in progress */ |
509 | if (!requests_init (info)) { |
510 | return NULL((void*)0); |
511 | } |
512 | |
513 | /* Defaults (just in case...) */ |
514 | /* Well, no just in case anymore. We may actually fail to fetch some |
515 | * fields. */ |
516 | info->forecast_type = prefs->type; |
517 | |
518 | info->temperature_unit = prefs->temperature_unit; |
519 | info->speed_unit = prefs->speed_unit; |
520 | info->pressure_unit = prefs->pressure_unit; |
521 | info->distance_unit = prefs->distance_unit; |
522 | |
523 | info->update = 0; |
524 | info->sky = -1; |
525 | info->cond.significant = FALSE(0); |
526 | info->cond.phenomenon = PHENOMENON_NONE; |
527 | info->cond.qualifier = QUALIFIER_NONE; |
528 | info->temp = -1000.0; |
529 | info->tempMinMaxValid = FALSE(0); |
530 | info->temp_min = -1000.0; |
531 | info->temp_max = -1000.0; |
532 | info->dew = -1000.0; |
533 | info->wind = -1; |
534 | info->windspeed = -1; |
535 | info->pressure = -1.0; |
536 | info->visibility = -1.0; |
537 | info->sunriseValid = FALSE(0); |
538 | info->sunsetValid = FALSE(0); |
539 | info->moonValid = FALSE(0); |
540 | info->sunrise = 0; |
541 | info->sunset = 0; |
542 | info->moonphase = 0; |
543 | info->moonlatitude = 0; |
544 | info->forecast = NULL((void*)0); |
545 | info->forecast_list = NULL((void*)0); |
546 | info->radar = NULL((void*)0); |
547 | info->radar_url = prefs->radar && prefs->radar_custom_url ? |
548 | g_strdup (prefs->radar_custom_url) : NULL((void*)0); |
549 | info->finish_cb = cb; |
550 | info->cb_data = data; |
551 | |
552 | if (!info->session) { |
553 | info->session = soup_session_new (); |
554 | } |
555 | |
556 | metar_start_open (info); |
557 | iwin_start_open (info); |
558 | |
559 | if (prefs->radar) { |
560 | wx_start_open (info); |
561 | } |
562 | |
563 | return info; |
564 | } |
565 | |
566 | void |
567 | weather_info_abort (WeatherInfo *info) |
568 | { |
569 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
570 | |
571 | if (info->session) { |
572 | soup_session_abort (info->session); |
573 | info->requests_pending = 0; |
574 | } |
575 | } |
576 | |
577 | WeatherInfo * |
578 | weather_info_clone (const WeatherInfo *info) |
579 | { |
580 | WeatherInfo *clone; |
581 | |
582 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
583 | |
584 | clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize __s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s )) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s ); __p; })); |
585 | |
586 | /* move everything */ |
587 | memmove (clone, info, sizeof (WeatherInfo)); |
588 | |
589 | /* special moves */ |
590 | clone->location = weather_location_clone (info->location); |
591 | /* This handles null correctly */ |
592 | clone->forecast = g_strdup (info->forecast); |
593 | clone->radar_url = g_strdup (info->radar_url); |
594 | |
595 | if (info->forecast_list) { |
596 | GSList *p; |
597 | |
598 | clone->forecast_list = NULL((void*)0); |
599 | for (p = info->forecast_list; p; p = p->next) { |
600 | clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data)); |
601 | } |
602 | |
603 | clone->forecast_list = g_slist_reverse (clone->forecast_list); |
604 | } |
605 | |
606 | clone->radar = info->radar; |
607 | if (clone->radar != NULL((void*)0)) |
608 | g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar )); |
609 | |
610 | return clone; |
611 | } |
612 | |
613 | void |
614 | weather_info_free (WeatherInfo *info) |
615 | { |
616 | if (!info) |
617 | return; |
618 | |
619 | weather_info_abort (info); |
620 | if (info->session) |
621 | g_object_unref (info->session); |
622 | |
623 | weather_location_free (info->location); |
624 | info->location = NULL((void*)0); |
625 | |
626 | g_free (info->forecast); |
627 | info->forecast = NULL((void*)0); |
628 | |
629 | free_forecast_list (info); |
630 | |
631 | if (info->radar != NULL((void*)0)) { |
632 | g_object_unref (info->radar); |
633 | info->radar = NULL((void*)0); |
634 | } |
635 | |
636 | g_free (info); |
637 | } |
638 | |
639 | gboolean |
640 | weather_info_is_valid (WeatherInfo *info) |
641 | { |
642 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
643 | return info->valid; |
644 | } |
645 | |
646 | gboolean |
647 | weather_info_network_error (WeatherInfo *info) |
648 | { |
649 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
650 | return info->network_error; |
651 | } |
652 | |
653 | void |
654 | weather_info_to_metric (WeatherInfo *info) |
655 | { |
656 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
657 | |
658 | info->temperature_unit = TEMP_UNIT_CENTIGRADE; |
659 | info->speed_unit = SPEED_UNIT_MS; |
660 | info->pressure_unit = PRESSURE_UNIT_HPA; |
661 | info->distance_unit = DISTANCE_UNIT_METERS; |
662 | } |
663 | |
664 | void |
665 | weather_info_to_imperial (WeatherInfo *info) |
666 | { |
667 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
668 | |
669 | info->temperature_unit = TEMP_UNIT_FAHRENHEIT; |
670 | info->speed_unit = SPEED_UNIT_MPH; |
671 | info->pressure_unit = PRESSURE_UNIT_INCH_HG; |
672 | info->distance_unit = DISTANCE_UNIT_MILES; |
673 | } |
674 | |
675 | const WeatherLocation * |
676 | weather_info_get_location (WeatherInfo *info) |
677 | { |
678 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
679 | return info->location; |
680 | } |
681 | |
682 | const gchar * |
683 | weather_info_get_location_name (WeatherInfo *info) |
684 | { |
685 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
686 | g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info->location != NULL" ); return (((void*)0)); } } while (0); |
687 | return info->location->name; |
688 | } |
689 | |
690 | const gchar * |
691 | weather_info_get_update (WeatherInfo *info) |
692 | { |
693 | static gchar buf[200]; |
694 | char *utf8, *timeformat; |
695 | |
696 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
697 | |
698 | if (!info->valid) |
699 | return "-"; |
700 | |
701 | if (info->update != 0) { |
702 | struct tm tm; |
703 | localtime_r (&info->update, &tm); |
704 | /* Translators: this is a format string for strftime |
705 | * see `man 3 strftime` for more details |
706 | */ |
707 | timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1, |
708 | NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
709 | if (!timeformat) { |
710 | strcpy (buf, "???"); |
711 | } |
712 | else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) { |
713 | strcpy (buf, "???"); |
714 | } |
715 | g_free (timeformat); |
716 | |
717 | /* Convert to UTF-8 */ |
718 | utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
719 | strcpy (buf, utf8); |
720 | g_free (utf8); |
721 | } else { |
722 | strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf)); |
723 | buf[sizeof (buf)-1] = '\0'; |
724 | } |
725 | |
726 | return buf; |
727 | } |
728 | |
729 | const gchar * |
730 | weather_info_get_sky (WeatherInfo *info) |
731 | { |
732 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
733 | if (!info->valid) |
734 | return "-"; |
735 | if (info->sky < 0) |
736 | return _("Unknown")(mateweather_gettext ("Unknown")); |
737 | return weather_sky_string (info->sky); |
738 | } |
739 | |
740 | const gchar * |
741 | weather_info_get_conditions (WeatherInfo *info) |
742 | { |
743 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
744 | if (!info->valid) |
745 | return "-"; |
746 | return weather_conditions_string (info->cond); |
747 | } |
748 | |
749 | static const gchar * |
750 | temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round) |
751 | { |
752 | static gchar buf[100]; |
753 | |
754 | switch (to_unit) { |
755 | case TEMP_UNIT_FAHRENHEIT: |
756 | if (!want_round) { |
757 | /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */ |
758 | g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp); |
759 | } else { |
760 | const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10; |
761 | gdouble temp_r; |
762 | |
763 | feclearexcept(range_problem); |
764 | temp_r = round (temp); |
765 | if (fetestexcept(range_problem)) |
766 | g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a"))); |
767 | else |
768 | /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */ |
769 | g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r); |
770 | } |
771 | break; |
772 | case TEMP_UNIT_CENTIGRADE: |
773 | if (!want_round) { |
774 | /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */ |
775 | g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0))); |
776 | } else { |
777 | const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10; |
778 | gdouble temp_r; |
779 | |
780 | feclearexcept(range_problem); |
781 | temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0))); |
782 | if (fetestexcept(range_problem)) |
783 | g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a"))); |
784 | else |
785 | /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */ |
786 | g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r); |
787 | } |
788 | break; |
789 | case TEMP_UNIT_KELVIN: |
790 | if (!want_round) { |
791 | /* Translators: This is the temperature in kelvin */ |
792 | g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0))); |
793 | } else { |
794 | const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10; |
795 | gdouble temp_r; |
796 | |
797 | feclearexcept(range_problem); |
798 | temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0))); |
799 | if (fetestexcept(range_problem)) |
800 | g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a"))); |
801 | else |
802 | /* Translators: This is the temperature in kelvin */ |
803 | g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r); |
804 | } |
805 | break; |
806 | |
807 | case TEMP_UNIT_INVALID: |
808 | case TEMP_UNIT_DEFAULT: |
809 | default: |
810 | g_warning ("Conversion to illegal temperature unit: %d", to_unit); |
811 | return _("Unknown")(mateweather_gettext ("Unknown")); |
812 | } |
813 | |
814 | return buf; |
815 | } |
816 | |
817 | const gchar * |
818 | weather_info_get_temp (WeatherInfo *info) |
819 | { |
820 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
821 | |
822 | if (!info->valid) |
823 | return "-"; |
824 | if (info->temp < -500.0) |
825 | return _("Unknown")(mateweather_gettext ("Unknown")); |
826 | |
827 | return temperature_string (info->temp, info->temperature_unit, FALSE(0)); |
828 | } |
829 | |
830 | const gchar * |
831 | weather_info_get_temp_min (WeatherInfo *info) |
832 | { |
833 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
834 | |
835 | if (!info->valid || !info->tempMinMaxValid) |
836 | return "-"; |
837 | if (info->temp_min < -500.0) |
838 | return _("Unknown")(mateweather_gettext ("Unknown")); |
839 | |
840 | return temperature_string (info->temp_min, info->temperature_unit, FALSE(0)); |
841 | } |
842 | |
843 | const gchar * |
844 | weather_info_get_temp_max (WeatherInfo *info) |
845 | { |
846 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
847 | |
848 | if (!info->valid || !info->tempMinMaxValid) |
849 | return "-"; |
850 | if (info->temp_max < -500.0) |
851 | return _("Unknown")(mateweather_gettext ("Unknown")); |
852 | |
853 | return temperature_string (info->temp_max, info->temperature_unit, FALSE(0)); |
854 | } |
855 | |
856 | const gchar * |
857 | weather_info_get_dew (WeatherInfo *info) |
858 | { |
859 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
860 | |
861 | if (!info->valid) |
862 | return "-"; |
863 | if (info->dew < -500.0) |
864 | return _("Unknown")(mateweather_gettext ("Unknown")); |
865 | |
866 | return temperature_string (info->dew, info->temperature_unit, FALSE(0)); |
867 | } |
868 | |
869 | const gchar * |
870 | weather_info_get_humidity (WeatherInfo *info) |
871 | { |
872 | static gchar buf[20]; |
873 | gdouble humidity; |
874 | |
875 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
876 | |
877 | if (!info->valid) |
878 | return "-"; |
879 | |
880 | humidity = calc_humidity (info->temp, info->dew); |
881 | if (humidity < 0.0) |
882 | return _("Unknown")(mateweather_gettext ("Unknown")); |
883 | |
884 | /* Translators: This is the humidity in percent */ |
885 | g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity); |
886 | return buf; |
887 | } |
888 | |
889 | const gchar * |
890 | weather_info_get_apparent (WeatherInfo *info) |
891 | { |
892 | gdouble apparent; |
893 | |
894 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
895 | if (!info->valid) |
896 | return "-"; |
897 | |
898 | apparent = calc_apparent (info); |
899 | if (apparent < -500.0) |
900 | return _("Unknown")(mateweather_gettext ("Unknown")); |
901 | |
902 | return temperature_string (apparent, info->temperature_unit, FALSE(0)); |
903 | } |
904 | |
905 | static const gchar * |
906 | windspeed_string (gfloat knots, SpeedUnit to_unit) |
907 | { |
908 | static gchar buf[100]; |
909 | |
910 | switch (to_unit) { |
911 | case SPEED_UNIT_KNOTS: |
912 | /* Translators: This is the wind speed in knots */ |
913 | g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots); |
914 | break; |
915 | case SPEED_UNIT_MPH: |
916 | /* Translators: This is the wind speed in miles per hour */ |
917 | g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779)); |
918 | break; |
919 | case SPEED_UNIT_KPH: |
920 | /* Translators: This is the wind speed in kilometers per hour */ |
921 | g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965)); |
922 | break; |
923 | case SPEED_UNIT_MS: |
924 | /* Translators: This is the wind speed in meters per second */ |
925 | g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444)); |
926 | break; |
927 | case SPEED_UNIT_BFT: |
928 | /* Translators: This is the wind speed as a Beaufort force factor |
929 | * (commonly used in nautical wind estimation). |
930 | */ |
931 | g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")), |
932 | WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666))); |
933 | break; |
934 | case SPEED_UNIT_INVALID: |
935 | case SPEED_UNIT_DEFAULT: |
936 | default: |
937 | g_warning ("Conversion to illegal speed unit: %d", to_unit); |
938 | return _("Unknown")(mateweather_gettext ("Unknown")); |
939 | } |
940 | |
941 | return buf; |
942 | } |
943 | |
944 | const gchar * |
945 | weather_info_get_wind (WeatherInfo *info) |
946 | { |
947 | static gchar buf[200]; |
948 | |
949 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
950 | |
951 | if (!info->valid) |
952 | return "-"; |
953 | if (info->windspeed < 0.0 || info->wind < 0) |
954 | return _("Unknown")(mateweather_gettext ("Unknown")); |
955 | if (info->windspeed == 0.00) { |
956 | strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf)); |
957 | buf[sizeof (buf)-1] = '\0'; |
958 | } else { |
959 | /* Translators: This is 'wind direction' / 'wind speed' */ |
960 | g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")), |
961 | weather_wind_direction_string (info->wind), |
962 | windspeed_string (info->windspeed, info->speed_unit)); |
963 | } |
964 | return buf; |
965 | } |
966 | |
967 | const gchar * |
968 | weather_info_get_pressure (WeatherInfo *info) |
969 | { |
970 | static gchar buf[100]; |
971 | |
972 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
973 | |
974 | if (!info->valid) |
975 | return "-"; |
976 | if (info->pressure < 0.0) |
977 | return _("Unknown")(mateweather_gettext ("Unknown")); |
978 | |
979 | switch (info->pressure_unit) { |
980 | case PRESSURE_UNIT_INCH_HG: |
981 | /* Translators: This is pressure in inches of mercury */ |
982 | g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure); |
983 | break; |
984 | case PRESSURE_UNIT_MM_HG: |
985 | /* Translators: This is pressure in millimeters of mercury */ |
986 | g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005)); |
987 | break; |
988 | case PRESSURE_UNIT_KPA: |
989 | /* Translators: This is pressure in kiloPascals */ |
990 | g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386)); |
991 | break; |
992 | case PRESSURE_UNIT_HPA: |
993 | /* Translators: This is pressure in hectoPascals */ |
994 | g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86)); |
995 | break; |
996 | case PRESSURE_UNIT_MB: |
997 | /* Translators: This is pressure in millibars */ |
998 | g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86))); |
999 | break; |
1000 | case PRESSURE_UNIT_ATM: |
1001 | /* Translators: This is pressure in atmospheres */ |
1002 | g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052)); |
1003 | break; |
1004 | |
1005 | case PRESSURE_UNIT_INVALID: |
1006 | case PRESSURE_UNIT_DEFAULT: |
1007 | default: |
1008 | g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit); |
1009 | return _("Unknown")(mateweather_gettext ("Unknown")); |
1010 | } |
1011 | |
1012 | return buf; |
1013 | } |
1014 | |
1015 | const gchar * |
1016 | weather_info_get_visibility (WeatherInfo *info) |
1017 | { |
1018 | static gchar buf[100]; |
1019 | |
1020 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1021 | |
1022 | if (!info->valid) |
1023 | return "-"; |
1024 | if (info->visibility < 0.0) |
1025 | return _("Unknown")(mateweather_gettext ("Unknown")); |
1026 | |
1027 | switch (info->distance_unit) { |
1028 | case DISTANCE_UNIT_MILES: |
1029 | /* Translators: This is the visibility in miles */ |
1030 | g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility); |
1031 | break; |
1032 | case DISTANCE_UNIT_KM: |
1033 | /* Translators: This is the visibility in kilometers */ |
1034 | g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344)); |
1035 | break; |
1036 | case DISTANCE_UNIT_METERS: |
1037 | /* Translators: This is the visibility in meters */ |
1038 | g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000)); |
1039 | break; |
1040 | |
1041 | case DISTANCE_UNIT_INVALID: |
1042 | case DISTANCE_UNIT_DEFAULT: |
1043 | default: |
1044 | g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit); |
1045 | return _("Unknown")(mateweather_gettext ("Unknown")); |
1046 | } |
1047 | |
1048 | return buf; |
1049 | } |
1050 | |
1051 | const gchar * |
1052 | weather_info_get_sunrise (WeatherInfo *info) |
1053 | { |
1054 | static gchar buf[200]; |
1055 | struct tm tm; |
1056 | |
1057 | g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info && info->location) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__ )), "info && info->location"); return (((void*)0)) ; } } while (0); |
1058 | |
1059 | if (!info->location->latlon_valid) |
1060 | return "-"; |
1061 | if (!info->valid) |
1062 | return "-"; |
1063 | if (!calc_sun (info)) |
1064 | return "-"; |
1065 | |
1066 | localtime_r (&info->sunrise, &tm); |
1067 | if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0) |
1068 | return "-"; |
1069 | return buf; |
1070 | } |
1071 | |
1072 | const gchar * |
1073 | weather_info_get_sunset (WeatherInfo *info) |
1074 | { |
1075 | static gchar buf[200]; |
1076 | struct tm tm; |
1077 | |
1078 | g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info && info->location) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__ )), "info && info->location"); return (((void*)0)) ; } } while (0); |
1079 | |
1080 | if (!info->location->latlon_valid) |
1081 | return "-"; |
1082 | if (!info->valid) |
1083 | return "-"; |
1084 | if (!calc_sun (info)) |
1085 | return "-"; |
1086 | |
1087 | localtime_r (&info->sunset, &tm); |
1088 | if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0) |
1089 | return "-"; |
1090 | return buf; |
1091 | } |
1092 | |
1093 | const gchar * |
1094 | weather_info_get_forecast (WeatherInfo *info) |
1095 | { |
1096 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1097 | return info->forecast; |
1098 | } |
1099 | |
1100 | /** |
1101 | * weather_info_get_forecast_list: |
1102 | * Returns list of WeatherInfo* objects for the forecast. |
1103 | * The list is owned by the 'info' object thus is alive as long |
1104 | * as the 'info'. This list is filled only when requested with |
1105 | * type FORECAST_LIST and if available for given location. |
1106 | * The 'update' property is the date/time when the forecast info |
1107 | * is used for. |
1108 | **/ |
1109 | GSList * |
1110 | weather_info_get_forecast_list (WeatherInfo *info) |
1111 | { |
1112 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1113 | |
1114 | if (!info->valid) |
1115 | return NULL((void*)0); |
1116 | |
1117 | return info->forecast_list; |
1118 | } |
1119 | |
1120 | GdkPixbufAnimation * |
1121 | weather_info_get_radar (WeatherInfo *info) |
1122 | { |
1123 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1124 | return info->radar; |
1125 | } |
1126 | |
1127 | const gchar * |
1128 | weather_info_get_temp_summary (WeatherInfo *info) |
1129 | { |
1130 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1131 | |
1132 | if (!info->valid || info->temp < -500.0) |
1133 | return "--"; |
1134 | |
1135 | return temperature_string (info->temp, info->temperature_unit, TRUE(!(0))); |
1136 | |
1137 | } |
1138 | |
1139 | gchar * |
1140 | weather_info_get_weather_summary (WeatherInfo *info) |
1141 | { |
1142 | const gchar *buf; |
1143 | |
1144 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1145 | |
1146 | if (!info->valid) |
1147 | return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed"))); |
1148 | buf = weather_info_get_conditions (info); |
1149 | if (!strcmp (buf, "-")) |
1150 | buf = weather_info_get_sky (info); |
1151 | return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf); |
1152 | } |
1153 | |
1154 | const gchar * |
1155 | weather_info_get_icon_name (WeatherInfo *info) |
1156 | { |
1157 | WeatherConditions cond; |
1158 | WeatherSky sky; |
1159 | time_t current_time; |
1160 | gboolean daytime; |
1161 | gchar* icon; |
1162 | static gchar icon_buffer[32]; |
1163 | WeatherMoonPhase moonPhase; |
1164 | WeatherMoonLatitude moonLat; |
1165 | gint phase; |
1166 | |
1167 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1168 | |
1169 | if (!info->valid) |
1170 | return NULL((void*)0); |
1171 | |
1172 | cond = info->cond; |
1173 | sky = info->sky; |
1174 | |
1175 | if (cond.significant) { |
1176 | if (cond.phenomenon != PHENOMENON_NONE && |
1177 | cond.qualifier == QUALIFIER_THUNDERSTORM) |
1178 | return "weather-storm"; |
1179 | |
1180 | switch (cond.phenomenon) { |
1181 | case PHENOMENON_INVALID: |
1182 | case PHENOMENON_LAST: |
1183 | case PHENOMENON_NONE: |
1184 | break; |
1185 | |
1186 | case PHENOMENON_DRIZZLE: |
1187 | case PHENOMENON_RAIN: |
1188 | case PHENOMENON_UNKNOWN_PRECIPITATION: |
1189 | case PHENOMENON_HAIL: |
1190 | case PHENOMENON_SMALL_HAIL: |
1191 | return "weather-showers"; |
1192 | |
1193 | case PHENOMENON_SNOW: |
1194 | case PHENOMENON_SNOW_GRAINS: |
1195 | case PHENOMENON_ICE_PELLETS: |
1196 | case PHENOMENON_ICE_CRYSTALS: |
1197 | return "weather-snow"; |
1198 | |
1199 | case PHENOMENON_TORNADO: |
1200 | case PHENOMENON_SQUALL: |
1201 | return "weather-storm"; |
1202 | |
1203 | case PHENOMENON_MIST: |
1204 | case PHENOMENON_FOG: |
1205 | case PHENOMENON_SMOKE: |
1206 | case PHENOMENON_VOLCANIC_ASH: |
1207 | case PHENOMENON_SAND: |
1208 | case PHENOMENON_HAZE: |
1209 | case PHENOMENON_SPRAY: |
1210 | case PHENOMENON_DUST: |
1211 | case PHENOMENON_SANDSTORM: |
1212 | case PHENOMENON_DUSTSTORM: |
1213 | case PHENOMENON_FUNNEL_CLOUD: |
1214 | case PHENOMENON_DUST_WHIRLS: |
1215 | return "weather-fog"; |
1216 | } |
1217 | } |
1218 | |
1219 | if (info->midnightSun || |
1220 | (!info->sunriseValid && !info->sunsetValid)) |
1221 | daytime = TRUE(!(0)); |
1222 | else if (info->polarNight) |
1223 | daytime = FALSE(0); |
1224 | else { |
1225 | current_time = time (NULL((void*)0)); |
1226 | daytime = |
1227 | ( !info->sunriseValid || (current_time >= info->sunrise) ) && |
1228 | ( !info->sunsetValid || (current_time < info->sunset) ); |
1229 | } |
1230 | |
1231 | switch (sky) { |
1232 | case SKY_INVALID: |
1233 | case SKY_LAST: |
1234 | case SKY_CLEAR: |
1235 | if (daytime) |
1236 | return "weather-clear"; |
1237 | else { |
1238 | icon = g_stpcpy(icon_buffer, "weather-clear-night"); |
1239 | break; |
1240 | } |
1241 | |
1242 | case SKY_BROKEN: |
1243 | case SKY_SCATTERED: |
1244 | case SKY_FEW: |
1245 | if (daytime) |
1246 | return "weather-few-clouds"; |
1247 | else { |
1248 | icon = g_stpcpy(icon_buffer, "weather-few-clouds-night"); |
1249 | break; |
1250 | } |
1251 | |
1252 | case SKY_OVERCAST: |
1253 | return "weather-overcast"; |
1254 | |
1255 | default: /* unrecognized */ |
1256 | return NULL((void*)0); |
1257 | } |
1258 | |
1259 | /* |
1260 | * A phase-of-moon icon is to be returned. |
1261 | * Determine which one based on the moon's location |
1262 | */ |
1263 | if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) { |
1264 | phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5); |
1265 | if (phase == MOON_PHASES36) { |
1266 | phase = 0; |
1267 | } else if (phase > 0 && |
1268 | (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846 ) |
1269 | < moonLat)) { |
1270 | /* |
1271 | * Locations south of the moon's latitude will see the moon in the |
1272 | * northern sky. The moon waxes and wanes from left to right |
1273 | * so we reference an icon running in the opposite direction. |
1274 | */ |
1275 | phase = MOON_PHASES36 - phase; |
1276 | } |
1277 | |
1278 | /* |
1279 | * If the moon is not full then append the angle to the icon string. |
1280 | * Note that an icon by this name is not required to exist: |
1281 | * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to |
1282 | * the full moon image. |
1283 | */ |
1284 | if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) { |
1285 | g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer), |
1286 | "-%03d", phase * 360 / MOON_PHASES36); |
1287 | } |
1288 | } |
1289 | return icon_buffer; |
1290 | } |
1291 | |
1292 | static gboolean |
1293 | temperature_value (gdouble temp_f, |
1294 | TempUnit to_unit, |
1295 | gdouble *value, |
1296 | TempUnit def_unit) |
1297 | { |
1298 | gboolean ok = TRUE(!(0)); |
1299 | |
1300 | *value = 0.0; |
1301 | if (temp_f < -500.0) |
1302 | return FALSE(0); |
1303 | |
1304 | if (to_unit == TEMP_UNIT_DEFAULT) |
1305 | to_unit = def_unit; |
1306 | |
1307 | switch (to_unit) { |
1308 | case TEMP_UNIT_FAHRENHEIT: |
1309 | *value = temp_f; |
1310 | break; |
1311 | case TEMP_UNIT_CENTIGRADE: |
1312 | *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0)); |
1313 | break; |
1314 | case TEMP_UNIT_KELVIN: |
1315 | *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0)); |
1316 | break; |
1317 | case TEMP_UNIT_INVALID: |
1318 | case TEMP_UNIT_DEFAULT: |
1319 | default: |
1320 | ok = FALSE(0); |
1321 | break; |
1322 | } |
1323 | |
1324 | return ok; |
1325 | } |
1326 | |
1327 | static gboolean |
1328 | speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit) |
1329 | { |
1330 | gboolean ok = TRUE(!(0)); |
1331 | |
1332 | *value = -1.0; |
1333 | |
1334 | if (knots < 0.0) |
1335 | return FALSE(0); |
1336 | |
1337 | if (to_unit == SPEED_UNIT_DEFAULT) |
1338 | to_unit = def_unit; |
1339 | |
1340 | switch (to_unit) { |
1341 | case SPEED_UNIT_KNOTS: |
1342 | *value = knots; |
1343 | break; |
1344 | case SPEED_UNIT_MPH: |
1345 | *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779); |
1346 | break; |
1347 | case SPEED_UNIT_KPH: |
1348 | *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965); |
1349 | break; |
1350 | case SPEED_UNIT_MS: |
1351 | *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444); |
1352 | break; |
1353 | case SPEED_UNIT_BFT: |
1354 | *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)); |
1355 | break; |
1356 | case SPEED_UNIT_INVALID: |
1357 | case SPEED_UNIT_DEFAULT: |
1358 | default: |
1359 | ok = FALSE(0); |
1360 | break; |
1361 | } |
1362 | |
1363 | return ok; |
1364 | } |
1365 | |
1366 | static gboolean |
1367 | pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit) |
1368 | { |
1369 | gboolean ok = TRUE(!(0)); |
1370 | |
1371 | *value = -1.0; |
1372 | |
1373 | if (inHg < 0.0) |
1374 | return FALSE(0); |
1375 | |
1376 | if (to_unit == PRESSURE_UNIT_DEFAULT) |
1377 | to_unit = def_unit; |
1378 | |
1379 | switch (to_unit) { |
1380 | case PRESSURE_UNIT_INCH_HG: |
1381 | *value = inHg; |
1382 | break; |
1383 | case PRESSURE_UNIT_MM_HG: |
1384 | *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005); |
1385 | break; |
1386 | case PRESSURE_UNIT_KPA: |
1387 | *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386); |
1388 | break; |
1389 | case PRESSURE_UNIT_HPA: |
1390 | *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86); |
1391 | break; |
1392 | case PRESSURE_UNIT_MB: |
1393 | *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86)); |
1394 | break; |
1395 | case PRESSURE_UNIT_ATM: |
1396 | *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052); |
1397 | break; |
1398 | case PRESSURE_UNIT_INVALID: |
1399 | case PRESSURE_UNIT_DEFAULT: |
1400 | default: |
1401 | ok = FALSE(0); |
1402 | break; |
1403 | } |
1404 | |
1405 | return ok; |
1406 | } |
1407 | |
1408 | static gboolean |
1409 | distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit) |
1410 | { |
1411 | gboolean ok = TRUE(!(0)); |
1412 | |
1413 | *value = -1.0; |
1414 | |
1415 | if (miles < 0.0) |
1416 | return FALSE(0); |
1417 | |
1418 | if (to_unit == DISTANCE_UNIT_DEFAULT) |
1419 | to_unit = def_unit; |
1420 | |
1421 | switch (to_unit) { |
1422 | case DISTANCE_UNIT_MILES: |
1423 | *value = miles; |
1424 | break; |
1425 | case DISTANCE_UNIT_KM: |
1426 | *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344); |
1427 | break; |
1428 | case DISTANCE_UNIT_METERS: |
1429 | *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000); |
1430 | break; |
1431 | case DISTANCE_UNIT_INVALID: |
1432 | case DISTANCE_UNIT_DEFAULT: |
1433 | default: |
1434 | ok = FALSE(0); |
1435 | break; |
1436 | } |
1437 | |
1438 | return ok; |
1439 | } |
1440 | |
1441 | gboolean |
1442 | weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky) |
1443 | { |
1444 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1445 | g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "sky != NULL"); return ((0)); } } while (0); |
1446 | |
1447 | if (!info->valid) |
1448 | return FALSE(0); |
1449 | |
1450 | if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST) |
1451 | return FALSE(0); |
1452 | |
1453 | *sky = info->sky; |
1454 | |
1455 | return TRUE(!(0)); |
1456 | } |
1457 | |
1458 | gboolean |
1459 | weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier) |
1460 | { |
1461 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1462 | g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "phenomenon != NULL" ); return ((0)); } } while (0); |
1463 | g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "qualifier != NULL" ); return ((0)); } } while (0); |
1464 | |
1465 | if (!info->valid) |
1466 | return FALSE(0); |
1467 | |
1468 | if (!info->cond.significant) |
1469 | return FALSE(0); |
1470 | |
1471 | if (!(info->cond.phenomenon > PHENOMENON_INVALID && |
1472 | info->cond.phenomenon < PHENOMENON_LAST && |
1473 | info->cond.qualifier > QUALIFIER_INVALID && |
1474 | info->cond.qualifier < QUALIFIER_LAST)) |
1475 | return FALSE(0); |
1476 | |
1477 | *phenomenon = info->cond.phenomenon; |
1478 | *qualifier = info->cond.qualifier; |
1479 | |
1480 | return TRUE(!(0)); |
1481 | } |
1482 | |
1483 | gboolean |
1484 | weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value) |
1485 | { |
1486 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1487 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1488 | |
1489 | if (!info->valid) |
1490 | return FALSE(0); |
1491 | |
1492 | return temperature_value (info->temp, unit, value, info->temperature_unit); |
1493 | } |
1494 | |
1495 | gboolean |
1496 | weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value) |
1497 | { |
1498 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1499 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1500 | |
1501 | if (!info->valid || !info->tempMinMaxValid) |
1502 | return FALSE(0); |
1503 | |
1504 | return temperature_value (info->temp_min, unit, value, info->temperature_unit); |
1505 | } |
1506 | |
1507 | gboolean |
1508 | weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value) |
1509 | { |
1510 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1511 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1512 | |
1513 | if (!info->valid || !info->tempMinMaxValid) |
1514 | return FALSE(0); |
1515 | |
1516 | return temperature_value (info->temp_max, unit, value, info->temperature_unit); |
1517 | } |
1518 | |
1519 | gboolean |
1520 | weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value) |
1521 | { |
1522 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1523 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1524 | |
1525 | if (!info->valid) |
1526 | return FALSE(0); |
1527 | |
1528 | return temperature_value (info->dew, unit, value, info->temperature_unit); |
1529 | } |
1530 | |
1531 | gboolean |
1532 | weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value) |
1533 | { |
1534 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1535 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1536 | |
1537 | if (!info->valid) |
1538 | return FALSE(0); |
1539 | |
1540 | return temperature_value (calc_apparent (info), unit, value, info->temperature_unit); |
1541 | } |
1542 | |
1543 | gboolean |
1544 | weather_info_get_value_update (WeatherInfo *info, time_t *value) |
1545 | { |
1546 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1547 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1548 | |
1549 | if (!info->valid) |
1550 | return FALSE(0); |
1551 | |
1552 | *value = info->update; |
1553 | |
1554 | return TRUE(!(0)); |
1555 | } |
1556 | |
1557 | gboolean |
1558 | weather_info_get_value_sunrise (WeatherInfo *info, time_t *value) |
1559 | { |
1560 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1561 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1562 | |
1563 | if (!info->valid || !info->sunriseValid) |
1564 | return FALSE(0); |
1565 | |
1566 | *value = info->sunrise; |
1567 | |
1568 | return TRUE(!(0)); |
1569 | } |
1570 | |
1571 | gboolean |
1572 | weather_info_get_value_sunset (WeatherInfo *info, time_t *value) |
1573 | { |
1574 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1575 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1576 | |
1577 | if (!info->valid || !info->sunsetValid) |
1578 | return FALSE(0); |
1579 | |
1580 | *value = info->sunset; |
1581 | |
1582 | return TRUE(!(0)); |
1583 | } |
1584 | |
1585 | gboolean |
1586 | weather_info_get_value_moonphase (WeatherInfo *info, |
1587 | WeatherMoonPhase *value, |
1588 | WeatherMoonLatitude *lat) |
1589 | { |
1590 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1591 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1592 | |
1593 | if (!info->valid || !info->moonValid) |
1594 | return FALSE(0); |
1595 | |
1596 | *value = info->moonphase; |
1597 | *lat = info->moonlatitude; |
1598 | |
1599 | return TRUE(!(0)); |
1600 | } |
1601 | |
1602 | gboolean |
1603 | weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction) |
1604 | { |
1605 | gboolean res = FALSE(0); |
1606 | |
1607 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1608 | g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "speed != NULL") ; return ((0)); } } while (0); |
1609 | g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "direction != NULL" ); return ((0)); } } while (0); |
1610 | |
1611 | if (!info->valid) |
1612 | return FALSE(0); |
1613 | |
1614 | if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST) |
1615 | return FALSE(0); |
1616 | |
1617 | res = speed_value (info->windspeed, unit, speed, info->speed_unit); |
1618 | *direction = info->wind; |
1619 | |
1620 | return res; |
1621 | } |
1622 | |
1623 | gboolean |
1624 | weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value) |
1625 | { |
1626 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1627 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1628 | |
1629 | if (!info->valid) |
1630 | return FALSE(0); |
1631 | |
1632 | return pressure_value (info->pressure, unit, value, info->pressure_unit); |
1633 | } |
1634 | |
1635 | gboolean |
1636 | weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value) |
1637 | { |
1638 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1639 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1640 | |
1641 | if (!info->valid) |
1642 | return FALSE(0); |
1643 | |
1644 | return distance_value (info->visibility, unit, value, info->distance_unit); |
1645 | } |
1646 | |
1647 | /** |
1648 | * weather_info_get_upcoming_moonphases: |
1649 | * @info: WeatherInfo containing the time_t of interest |
1650 | * @phases: An array of four time_t values that will hold the returned values. |
1651 | * The values are estimates of the time of the next new, quarter, full and |
1652 | * three-quarter moons. |
1653 | * |
1654 | * Returns: gboolean indicating success or failure |
1655 | */ |
1656 | gboolean |
1657 | weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases) |
1658 | { |
1659 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1660 | g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "phases != NULL" ); return ((0)); } } while (0); |
1661 | |
1662 | return calc_moon_phases(info, phases); |
1663 | } |
1664 | |
1665 | static void |
1666 | _weather_internal_check (void) |
1667 | { |
1668 | g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str )[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c", 1668, ((const char*) (__func__) ), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while (0); |
1669 | g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c" , 1669, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST" ); } while (0); |
1670 | g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0]) ) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c", 1670, ((const char*) (__func__) ), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while (0); |
1671 | g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0 ])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c", 1671, ((const char*) (__func__) ), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while (0); |
1672 | } |
File: | weather-metar.c |
Warning: | line 169, column 24 Out of bound memory access (access exceeds upper limit of memory block) |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ | |||
2 | /* weather-metar.c - Weather server functions (METAR) | |||
3 | * | |||
4 | * This program is free software; you can redistribute it and/or | |||
5 | * modify it under the terms of the GNU General Public License as | |||
6 | * published by the Free Software Foundation; either version 2 of the | |||
7 | * License, or (at your option) any later version. | |||
8 | * | |||
9 | * This program is distributed in the hope that it will be useful, but | |||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
12 | * General Public License for more details. | |||
13 | * | |||
14 | * You should have received a copy of the GNU General Public License | |||
15 | * along with this program; if not, see | |||
16 | * <http://www.gnu.org/licenses/>. | |||
17 | */ | |||
18 | ||||
19 | #ifdef HAVE_CONFIG_H1 | |||
20 | #include <config.h> | |||
21 | #endif | |||
22 | ||||
23 | #include <stdlib.h> | |||
24 | #include <string.h> | |||
25 | #include <sys/types.h> | |||
26 | #include <regex.h> | |||
27 | ||||
28 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE | |||
29 | #include "weather.h" | |||
30 | #include "weather-priv.h" | |||
31 | ||||
32 | enum { | |||
33 | TIME_RE, | |||
34 | WIND_RE, | |||
35 | VIS_RE, | |||
36 | COND_RE, | |||
37 | CLOUD_RE, | |||
38 | TEMP_RE, | |||
39 | PRES_RE, | |||
40 | ||||
41 | RE_NUM | |||
42 | }; | |||
43 | ||||
44 | /* Return time of weather report as secs since epoch UTC */ | |||
45 | static time_t | |||
46 | make_time (gint utcDate, gint utcHour, gint utcMin) | |||
47 | { | |||
48 | const time_t now = time (NULL((void*)0)); | |||
49 | struct tm tm; | |||
50 | ||||
51 | localtime_r (&now, &tm); | |||
52 | ||||
53 | /* If last reading took place just before midnight UTC on the | |||
54 | * first, adjust the date downward to allow for the month | |||
55 | * change-over. This ASSUMES that the reading won't be more than | |||
56 | * 24 hrs old! */ | |||
57 | if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) { | |||
58 | tm.tm_mday = 0; /* mktime knows this is the last day of the previous | |||
59 | * month. */ | |||
60 | } else { | |||
61 | tm.tm_mday = utcDate; | |||
62 | } | |||
63 | tm.tm_hour = utcHour; | |||
64 | tm.tm_min = utcMin; | |||
65 | tm.tm_sec = 0; | |||
66 | ||||
67 | /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */ | |||
68 | #ifdef HAVE_TM_TM_GMOFF1 | |||
69 | return tm.tm_gmtoff + mktime (&tm); | |||
70 | #elif defined HAVE_TIMEZONE | |||
71 | return timezone + mktime (&tm); | |||
72 | #endif | |||
73 | } | |||
74 | ||||
75 | static void | |||
76 | metar_tok_time (gchar *tokp, WeatherInfo *info) | |||
77 | { | |||
78 | gint day, hr, min; | |||
79 | ||||
80 | sscanf (tokp, "%2u%2u%2u", &day, &hr, &min); | |||
81 | info->update = make_time (day, hr, min); | |||
82 | } | |||
83 | ||||
84 | static void | |||
85 | metar_tok_wind (gchar *tokp, WeatherInfo *info) | |||
86 | { | |||
87 | gchar sdir[4], sspd[4], sgust[4]; | |||
88 | gint dir, spd = -1; | |||
89 | gchar *gustp; | |||
90 | size_t glen; | |||
91 | ||||
92 | strncpy (sdir, tokp, 3); | |||
93 | sdir[3] = 0; | |||
94 | dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir); | |||
95 | ||||
96 | memset (sspd, 0, sizeof (sspd)); | |||
97 | glen = strspn (tokp + 3, CONST_DIGITS"0123456789"); | |||
98 | strncpy (sspd, tokp + 3, glen); | |||
99 | spd = atoi (sspd); | |||
100 | tokp += glen + 3; | |||
101 | ||||
102 | gustp = strchr (tokp, 'G'); | |||
103 | if (gustp) { | |||
104 | memset (sgust, 0, sizeof (sgust)); | |||
105 | glen = strspn (gustp + 1, CONST_DIGITS"0123456789"); | |||
106 | strncpy (sgust, gustp + 1, glen); | |||
107 | tokp = gustp + 1 + glen; | |||
108 | } | |||
109 | ||||
110 | if (!strcmp (tokp, "MPS")) | |||
111 | info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444); | |||
112 | else | |||
113 | info->windspeed = (WeatherWindSpeed)spd; | |||
114 | ||||
115 | if ((349 <= dir) || (dir <= 11)) | |||
116 | info->wind = WIND_N; | |||
117 | else if ((12 <= dir) && (dir <= 33)) | |||
118 | info->wind = WIND_NNE; | |||
119 | else if ((34 <= dir) && (dir <= 56)) | |||
120 | info->wind = WIND_NE; | |||
121 | else if ((57 <= dir) && (dir <= 78)) | |||
122 | info->wind = WIND_ENE; | |||
123 | else if ((79 <= dir) && (dir <= 101)) | |||
124 | info->wind = WIND_E; | |||
125 | else if ((102 <= dir) && (dir <= 123)) | |||
126 | info->wind = WIND_ESE; | |||
127 | else if ((124 <= dir) && (dir <= 146)) | |||
128 | info->wind = WIND_SE; | |||
129 | else if ((147 <= dir) && (dir <= 168)) | |||
130 | info->wind = WIND_SSE; | |||
131 | else if ((169 <= dir) && (dir <= 191)) | |||
132 | info->wind = WIND_S; | |||
133 | else if ((192 <= dir) && (dir <= 213)) | |||
134 | info->wind = WIND_SSW; | |||
135 | else if ((214 <= dir) && (dir <= 236)) | |||
136 | info->wind = WIND_SW; | |||
137 | else if ((237 <= dir) && (dir <= 258)) | |||
138 | info->wind = WIND_WSW; | |||
139 | else if ((259 <= dir) && (dir <= 281)) | |||
140 | info->wind = WIND_W; | |||
141 | else if ((282 <= dir) && (dir <= 303)) | |||
142 | info->wind = WIND_WNW; | |||
143 | else if ((304 <= dir) && (dir <= 326)) | |||
144 | info->wind = WIND_NW; | |||
145 | else if ((327 <= dir) && (dir <= 348)) | |||
146 | info->wind = WIND_NNW; | |||
147 | } | |||
148 | ||||
149 | static void | |||
150 | metar_tok_vis (gchar *tokp, WeatherInfo *info) | |||
151 | { | |||
152 | gchar *pfrac, *pend, *psp; | |||
153 | gchar sval[6]; | |||
154 | gint num, den, val; | |||
155 | ||||
156 | memset (sval, 0, sizeof (sval)); | |||
157 | ||||
158 | if (!strcmp (tokp,"CAVOK")) { | |||
| ||||
159 | // "Ceiling And Visibility OK": visibility >= 10 KM | |||
160 | info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000); | |||
161 | info->sky = SKY_CLEAR; | |||
162 | } else if (0 != (pend = strstr (tokp, "SM"))) { | |||
163 | // US observation: field ends with "SM" | |||
164 | pfrac = strchr (tokp, '/'); | |||
165 | if (pfrac) { | |||
166 | if (*tokp == 'M') { | |||
167 | info->visibility = 0.001; | |||
168 | } else { | |||
169 | num = (*(pfrac - 1) - '0'); | |||
| ||||
170 | strncpy (sval, pfrac + 1, pend - pfrac - 1); | |||
171 | den = atoi (sval); | |||
172 | info->visibility = | |||
173 | ((WeatherVisibility)num / ((WeatherVisibility)den)); | |||
174 | ||||
175 | psp = strchr (tokp, ' '); | |||
176 | if (psp) { | |||
177 | *psp = '\0'; | |||
178 | val = atoi (tokp); | |||
179 | info->visibility += (WeatherVisibility)val; | |||
180 | } | |||
181 | } | |||
182 | } else { | |||
183 | strncpy (sval, tokp, pend - tokp); | |||
184 | val = atoi (sval); | |||
185 | info->visibility = (WeatherVisibility)val; | |||
186 | } | |||
187 | } else { | |||
188 | // International observation: NNNN(DD NNNNDD)? | |||
189 | // For now: use only the minimum visibility and ignore its direction | |||
190 | strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789")); | |||
191 | val = atoi (sval); | |||
192 | info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000); | |||
193 | } | |||
194 | } | |||
195 | ||||
196 | static void | |||
197 | metar_tok_cloud (gchar *tokp, WeatherInfo *info) | |||
198 | { | |||
199 | gchar stype[4], salt[4]; | |||
200 | ||||
201 | strncpy (stype, tokp, 3); | |||
202 | stype[3] = 0; | |||
203 | if (strlen (tokp) == 6) { | |||
204 | strncpy (salt, tokp + 3, 3); | |||
205 | salt[3] = 0; | |||
206 | } | |||
207 | ||||
208 | if (!strcmp (stype, "CLR")) { | |||
209 | info->sky = SKY_CLEAR; | |||
210 | } else if (!strcmp (stype, "SKC")) { | |||
211 | info->sky = SKY_CLEAR; | |||
212 | } else if (!strcmp (stype, "NSC")) { | |||
213 | info->sky = SKY_CLEAR; | |||
214 | } else if (!strcmp (stype, "BKN")) { | |||
215 | info->sky = SKY_BROKEN; | |||
216 | } else if (!strcmp (stype, "SCT")) { | |||
217 | info->sky = SKY_SCATTERED; | |||
218 | } else if (!strcmp (stype, "FEW")) { | |||
219 | info->sky = SKY_FEW; | |||
220 | } else if (!strcmp (stype, "OVC")) { | |||
221 | info->sky = SKY_OVERCAST; | |||
222 | } | |||
223 | } | |||
224 | ||||
225 | static void | |||
226 | metar_tok_pres (gchar *tokp, WeatherInfo *info) | |||
227 | { | |||
228 | if (*tokp == 'A') { | |||
229 | gchar sintg[3], sfract[3]; | |||
230 | gint intg, fract; | |||
231 | ||||
232 | strncpy (sintg, tokp + 1, 2); | |||
233 | sintg[2] = 0; | |||
234 | intg = atoi (sintg); | |||
235 | ||||
236 | strncpy (sfract, tokp + 3, 2); | |||
237 | sfract[2] = 0; | |||
238 | fract = atoi (sfract); | |||
239 | ||||
240 | info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0); | |||
241 | } else { /* *tokp == 'Q' */ | |||
242 | gchar spres[5]; | |||
243 | gint pres; | |||
244 | ||||
245 | strncpy (spres, tokp + 1, 4); | |||
246 | spres[4] = 0; | |||
247 | pres = atoi (spres); | |||
248 | ||||
249 | info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373); | |||
250 | } | |||
251 | } | |||
252 | ||||
253 | static void | |||
254 | metar_tok_temp (gchar *tokp, WeatherInfo *info) | |||
255 | { | |||
256 | gchar *ptemp, *pdew, *psep; | |||
257 | ||||
258 | psep = strchr (tokp, '/'); | |||
259 | *psep = 0; | |||
260 | ptemp = tokp; | |||
261 | pdew = psep + 1; | |||
262 | ||||
263 | info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0) | |||
264 | : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0); | |||
265 | if (*pdew) { | |||
266 | info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0) | |||
267 | : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0); | |||
268 | } else { | |||
269 | info->dew = -1000.0; | |||
270 | } | |||
271 | } | |||
272 | ||||
273 | static void | |||
274 | metar_tok_cond (gchar *tokp, WeatherInfo *info) | |||
275 | { | |||
276 | gchar squal[3], sphen[4]; | |||
277 | gchar *pphen; | |||
278 | ||||
279 | if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-'))) | |||
280 | ++tokp; /* FIX */ | |||
281 | ||||
282 | if ((*tokp == '+') || (*tokp == '-')) | |||
283 | pphen = tokp + 1; | |||
284 | else if (strlen (tokp) < 4) | |||
285 | pphen = tokp; | |||
286 | else | |||
287 | pphen = tokp + 2; | |||
288 | ||||
289 | memset (squal, 0, sizeof (squal)); | |||
290 | strncpy (squal, tokp, pphen - tokp); | |||
291 | squal[pphen - tokp] = 0; | |||
292 | ||||
293 | memset (sphen, 0, sizeof (sphen)); | |||
294 | strncpy (sphen, pphen, sizeof (sphen)); | |||
295 | sphen[sizeof (sphen)-1] = '\0'; | |||
296 | ||||
297 | /* Defaults */ | |||
298 | info->cond.qualifier = QUALIFIER_NONE; | |||
299 | info->cond.phenomenon = PHENOMENON_NONE; | |||
300 | info->cond.significant = FALSE(0); | |||
301 | ||||
302 | if (!strcmp (squal, "")) { | |||
303 | info->cond.qualifier = QUALIFIER_MODERATE; | |||
304 | } else if (!strcmp (squal, "-")) { | |||
305 | info->cond.qualifier = QUALIFIER_LIGHT; | |||
306 | } else if (!strcmp (squal, "+")) { | |||
307 | info->cond.qualifier = QUALIFIER_HEAVY; | |||
308 | } else if (!strcmp (squal, "VC")) { | |||
309 | info->cond.qualifier = QUALIFIER_VICINITY; | |||
310 | } else if (!strcmp (squal, "MI")) { | |||
311 | info->cond.qualifier = QUALIFIER_SHALLOW; | |||
312 | } else if (!strcmp (squal, "BC")) { | |||
313 | info->cond.qualifier = QUALIFIER_PATCHES; | |||
314 | } else if (!strcmp (squal, "PR")) { | |||
315 | info->cond.qualifier = QUALIFIER_PARTIAL; | |||
316 | } else if (!strcmp (squal, "TS")) { | |||
317 | info->cond.qualifier = QUALIFIER_THUNDERSTORM; | |||
318 | } else if (!strcmp (squal, "BL")) { | |||
319 | info->cond.qualifier = QUALIFIER_BLOWING; | |||
320 | } else if (!strcmp (squal, "SH")) { | |||
321 | info->cond.qualifier = QUALIFIER_SHOWERS; | |||
322 | } else if (!strcmp (squal, "DR")) { | |||
323 | info->cond.qualifier = QUALIFIER_DRIFTING; | |||
324 | } else if (!strcmp (squal, "FZ")) { | |||
325 | info->cond.qualifier = QUALIFIER_FREEZING; | |||
326 | } else { | |||
327 | return; | |||
328 | } | |||
329 | ||||
330 | if (!strcmp (sphen, "DZ")) { | |||
331 | info->cond.phenomenon = PHENOMENON_DRIZZLE; | |||
332 | } else if (!strcmp (sphen, "RA")) { | |||
333 | info->cond.phenomenon = PHENOMENON_RAIN; | |||
334 | } else if (!strcmp (sphen, "SN")) { | |||
335 | info->cond.phenomenon = PHENOMENON_SNOW; | |||
336 | } else if (!strcmp (sphen, "SG")) { | |||
337 | info->cond.phenomenon = PHENOMENON_SNOW_GRAINS; | |||
338 | } else if (!strcmp (sphen, "IC")) { | |||
339 | info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS; | |||
340 | } else if (!strcmp (sphen, "PE")) { | |||
341 | info->cond.phenomenon = PHENOMENON_ICE_PELLETS; | |||
342 | } else if (!strcmp (sphen, "GR")) { | |||
343 | info->cond.phenomenon = PHENOMENON_HAIL; | |||
344 | } else if (!strcmp (sphen, "GS")) { | |||
345 | info->cond.phenomenon = PHENOMENON_SMALL_HAIL; | |||
346 | } else if (!strcmp (sphen, "UP")) { | |||
347 | info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION; | |||
348 | } else if (!strcmp (sphen, "BR")) { | |||
349 | info->cond.phenomenon = PHENOMENON_MIST; | |||
350 | } else if (!strcmp (sphen, "FG")) { | |||
351 | info->cond.phenomenon = PHENOMENON_FOG; | |||
352 | } else if (!strcmp (sphen, "FU")) { | |||
353 | info->cond.phenomenon = PHENOMENON_SMOKE; | |||
354 | } else if (!strcmp (sphen, "VA")) { | |||
355 | info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH; | |||
356 | } else if (!strcmp (sphen, "SA")) { | |||
357 | info->cond.phenomenon = PHENOMENON_SAND; | |||
358 | } else if (!strcmp (sphen, "HZ")) { | |||
359 | info->cond.phenomenon = PHENOMENON_HAZE; | |||
360 | } else if (!strcmp (sphen, "PY")) { | |||
361 | info->cond.phenomenon = PHENOMENON_SPRAY; | |||
362 | } else if (!strcmp (sphen, "DU")) { | |||
363 | info->cond.phenomenon = PHENOMENON_DUST; | |||
364 | } else if (!strcmp (sphen, "SQ")) { | |||
365 | info->cond.phenomenon = PHENOMENON_SQUALL; | |||
366 | } else if (!strcmp (sphen, "SS")) { | |||
367 | info->cond.phenomenon = PHENOMENON_SANDSTORM; | |||
368 | } else if (!strcmp (sphen, "DS")) { | |||
369 | info->cond.phenomenon = PHENOMENON_DUSTSTORM; | |||
370 | } else if (!strcmp (sphen, "PO")) { | |||
371 | info->cond.phenomenon = PHENOMENON_DUST_WHIRLS; | |||
372 | } else if (!strcmp (sphen, "+FC")) { | |||
373 | info->cond.phenomenon = PHENOMENON_TORNADO; | |||
374 | } else if (!strcmp (sphen, "FC")) { | |||
375 | info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD; | |||
376 | } else { | |||
377 | return; | |||
378 | } | |||
379 | ||||
380 | if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE)) | |||
381 | info->cond.significant = TRUE(!(0)); | |||
382 | } | |||
383 | ||||
384 | #define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z" | |||
385 | #define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" | |||
386 | #define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" "CAVOK" "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \ | |||
387 | "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \ | |||
388 | "CAVOK" | |||
389 | #define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" | |||
390 | #define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" | |||
391 | #define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" | |||
392 | #define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})" | |||
393 | ||||
394 | /* POSIX regular expressions do not allow us to express "match whole words | |||
395 | * only" in a simple way, so we have to wrap them all into | |||
396 | * (^| )(...regex...)( |$) | |||
397 | */ | |||
398 | #define RE_PREFIX"(^| )(" "(^| )(" | |||
399 | #define RE_SUFFIX")( |$)" ")( |$)" | |||
400 | ||||
401 | static regex_t metar_re[RE_NUM]; | |||
402 | static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info); | |||
403 | ||||
404 | static void | |||
405 | metar_init_re (void) | |||
406 | { | |||
407 | static gboolean initialized = FALSE(0); | |||
408 | if (initialized) | |||
409 | return; | |||
410 | initialized = TRUE(!(0)); | |||
411 | ||||
412 | regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1); | |||
413 | regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1); | |||
414 | regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" "CAVOK" RE_SUFFIX")( |$)", REG_EXTENDED1); | |||
415 | regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1); | |||
416 | regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1); | |||
417 | regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1); | |||
418 | regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1); | |||
419 | ||||
420 | metar_f[TIME_RE] = metar_tok_time; | |||
421 | metar_f[WIND_RE] = metar_tok_wind; | |||
422 | metar_f[VIS_RE] = metar_tok_vis; | |||
423 | metar_f[COND_RE] = metar_tok_cond; | |||
424 | metar_f[CLOUD_RE] = metar_tok_cloud; | |||
425 | metar_f[TEMP_RE] = metar_tok_temp; | |||
426 | metar_f[PRES_RE] = metar_tok_pres; | |||
427 | } | |||
428 | ||||
429 | gboolean | |||
430 | metar_parse (gchar *metar, WeatherInfo *info) | |||
431 | { | |||
432 | gchar *p; | |||
433 | //gchar *rmk; | |||
434 | gint i, i2; | |||
435 | regmatch_t rm, rm2; | |||
436 | gchar *tokp; | |||
437 | ||||
438 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); | |||
439 | g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "metar != NULL") ; return ((0)); } } while (0); | |||
440 | ||||
441 | metar_init_re (); | |||
442 | ||||
443 | /* | |||
444 | * Force parsing to end at "RMK" field. This prevents a subtle | |||
445 | * problem when info within the remark happens to match an earlier state | |||
446 | * and, as a result, throws off all the remaining expression | |||
447 | */ | |||
448 | if (0 != (p = strstr (metar, " RMK "))) { | |||
449 | *p = '\0'; | |||
450 | //rmk = p + 5; // uncomment this if RMK data becomes useful | |||
451 | } | |||
452 | ||||
453 | p = metar; | |||
454 | i = TIME_RE; | |||
455 | while (*p) { | |||
456 | ||||
457 | i2 = RE_NUM; | |||
458 | rm2.rm_so = strlen (p); | |||
459 | rm2.rm_eo = rm2.rm_so; | |||
460 | ||||
461 | for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) { | |||
462 | if (0 == regexec (&metar_re[i], p, 1, &rm, 0) | |||
463 | && rm.rm_so < rm2.rm_so) | |||
464 | { | |||
465 | i2 = i; | |||
466 | /* Skip leading and trailing space characters, if present. | |||
467 | (the regular expressions include those characters to | |||
468 | only get matches limited to whole words). */ | |||
469 | if (p[rm.rm_so] == ' ') rm.rm_so++; | |||
470 | if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--; | |||
471 | rm2.rm_so = rm.rm_so; | |||
472 | rm2.rm_eo = rm.rm_eo; | |||
473 | } | |||
474 | } | |||
475 | ||||
476 | if (i2 != RE_NUM) { | |||
477 | tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so); | |||
478 | metar_f[i2] (tokp, info); | |||
479 | g_free (tokp); | |||
480 | } | |||
481 | ||||
482 | p += rm2.rm_eo; | |||
483 | p += strspn (p, " "); | |||
484 | } | |||
485 | return TRUE(!(0)); | |||
486 | } | |||
487 | ||||
488 | static void | |||
489 | metar_finish (SoupSession *session, SoupMessage *msg, gpointer data) | |||
490 | { | |||
491 | WeatherInfo *info = (WeatherInfo *)data; | |||
492 | WeatherLocation *loc; | |||
493 | const gchar *p, *endtag; | |||
494 | gchar *searchkey, *metar; | |||
495 | gboolean success = FALSE(0); | |||
496 | ||||
497 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); | |||
498 | ||||
499 | if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code ) < 300)) { | |||
500 | if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code ) < 100)) | |||
501 | info->network_error = TRUE(!(0)); | |||
502 | else { | |||
503 | /* Translators: %d is an error code, and %s the error string */ | |||
504 | g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")), | |||
505 | msg->status_code, msg->reason_phrase); | |||
506 | } | |||
507 | request_done (info, FALSE(0)); | |||
508 | return; | |||
509 | } | |||
510 | ||||
511 | loc = info->location; | |||
512 | ||||
513 | searchkey = g_strdup_printf ("<raw_text>%s", loc->code); | |||
514 | p = strstr (msg->response_body->data, searchkey); | |||
515 | g_free (searchkey); | |||
516 | if (p) { | |||
517 | p += WEATHER_LOCATION_CODE_LEN4 + 11; | |||
518 | endtag = strstr (p, "</raw_text>"); | |||
519 | if (endtag) | |||
520 | metar = g_strndup (p, endtag - p); | |||
521 | else | |||
522 | metar = g_strdup (p); | |||
523 | success = metar_parse (metar, info); | |||
524 | g_free (metar); | |||
525 | } else if (!strstr (msg->response_body->data, "aviationweather.gov")) { | |||
526 | /* The response doesn't even seem to have come from NOAA... | |||
527 | * most likely it is a wifi hotspot login page. Call that a | |||
528 | * network error. | |||
529 | */ | |||
530 | info->network_error = TRUE(!(0)); | |||
531 | } | |||
532 | ||||
533 | info->valid = success; | |||
534 | request_done (info, TRUE(!(0))); | |||
535 | } | |||
536 | ||||
537 | /* Read current conditions and fill in info structure */ | |||
538 | void | |||
539 | metar_start_open (WeatherInfo *info) | |||
540 | { | |||
541 | WeatherLocation *loc; | |||
542 | SoupMessage *msg; | |||
543 | ||||
544 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); | |||
545 | info->valid = info->network_error = FALSE(0); | |||
546 | loc = info->location; | |||
547 | if (loc == NULL((void*)0)) { | |||
548 | g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location"))); | |||
549 | return; | |||
550 | } | |||
551 | ||||
552 | msg = soup_form_request_new ( | |||
553 | "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam", | |||
554 | "dataSource", "metars", | |||
555 | "requestType", "retrieve", | |||
556 | "format", "xml", | |||
557 | "hoursBeforeNow", "3", | |||
558 | "mostRecent", "true", | |||
559 | "fields", "raw_text", | |||
560 | "stationString", loc->code, | |||
561 | NULL((void*)0)); | |||
562 | soup_session_queue_message (info->session, msg, metar_finish, info); | |||
563 | ||||
564 | info->requests_pending++; | |||
565 | } |
File: | weather.c |
Warning: | line 719, column 2 Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119 |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | /* weather.c - Overall weather server functions |
3 | * |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License as |
6 | * published by the Free Software Foundation; either version 2 of the |
7 | * License, or (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, see |
16 | * <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #ifdef HAVE_CONFIG_H1 |
20 | #include <config.h> |
21 | #endif |
22 | |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <assert.h> |
26 | #include <string.h> |
27 | #include <ctype.h> |
28 | #include <math.h> |
29 | #include <fenv.h> |
30 | |
31 | #ifdef HAVE_VALUES_H |
32 | #include <values.h> |
33 | #endif |
34 | |
35 | #include <time.h> |
36 | #include <unistd.h> |
37 | |
38 | #include <gdk-pixbuf/gdk-pixbuf.h> |
39 | |
40 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE |
41 | #include "weather.h" |
42 | #include "weather-priv.h" |
43 | |
44 | #define MOON_PHASES36 36 |
45 | |
46 | /** |
47 | * SECTION:weather |
48 | * @Title: weather |
49 | */ |
50 | |
51 | static void _weather_internal_check (void); |
52 | |
53 | static inline void |
54 | mateweather_gettext_init (void) |
55 | { |
56 | static gsize mateweather_gettext_initialized = FALSE(0); |
57 | |
58 | if (G_UNLIKELY (g_once_init_enter (&mateweather_gettext_initialized))(__builtin_expect (__extension__ ({ int _g_boolean_var_; if ( (__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized ) == sizeof (gpointer), "Expression evaluates to false"); (void ) (0 ? (gpointer) *(&mateweather_gettext_initialized) : ( (void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(& mateweather_gettext_initialized) == sizeof (gpointer), "Expression evaluates to false" ); __typeof__ (*(&mateweather_gettext_initialized)) gapg_temp_newval ; __typeof__ ((&mateweather_gettext_initialized)) gapg_temp_atomic = (&mateweather_gettext_initialized); __atomic_load (gapg_temp_atomic , &gapg_temp_newval, 5); gapg_temp_newval; })) && g_once_init_enter (&mateweather_gettext_initialized)); } ))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 0))) { |
59 | bindtextdomain (GETTEXT_PACKAGE"libmateweather", MATELOCALEDIR"/usr/local/share/locale"); |
60 | #ifdef HAVE_BIND_TEXTDOMAIN_CODESET |
61 | bind_textdomain_codeset (GETTEXT_PACKAGE"libmateweather", "UTF-8"); |
62 | #endif |
63 | g_once_init_leave (&mateweather_gettext_initialized, TRUE)(__extension__ ({ _Static_assert (sizeof *(&mateweather_gettext_initialized ) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void) (*(&mateweather_gettext_initialized) = ((!(0)))) : (void) 0; g_once_init_leave ((&mateweather_gettext_initialized ), (gsize) ((!(0)))); })); |
64 | } |
65 | } |
66 | |
67 | const char * |
68 | mateweather_gettext (const char *str) |
69 | { |
70 | mateweather_gettext_init (); |
71 | return dgettext (GETTEXT_PACKAGE, str)dcgettext ("libmateweather", str, 5); |
72 | } |
73 | |
74 | const char * |
75 | mateweather_dpgettext (const char *context, |
76 | const char *str) |
77 | { |
78 | mateweather_gettext_init (); |
79 | return g_dpgettext2 (GETTEXT_PACKAGE"libmateweather", context, str); |
80 | } |
81 | |
82 | /* |
83 | * Convert string of the form "DD-MM-SSH" to radians |
84 | * DD:degrees (to 3 digits), MM:minutes, SS:seconds H:hemisphere (NESW) |
85 | * Return value is positive for N,E; negative for S,W. |
86 | */ |
87 | static gdouble |
88 | dmsh2rad (const gchar *latlon) |
89 | { |
90 | char *p1, *p2; |
91 | int deg, min, sec, dir; |
92 | gdouble value; |
93 | |
94 | if (latlon == NULL((void*)0)) |
95 | return DBL_MAX1.7976931348623157e+308; |
96 | p1 = strchr (latlon, '-'); |
97 | p2 = strrchr (latlon, '-'); |
98 | if (p1 == NULL((void*)0) || p1 == latlon) { |
99 | return DBL_MAX1.7976931348623157e+308; |
100 | } else if (p1 == p2) { |
101 | sscanf (latlon, "%d-%d", °, &min); |
102 | sec = 0; |
103 | } else if (p2 == 1 + p1) { |
104 | return DBL_MAX1.7976931348623157e+308; |
105 | } else { |
106 | sscanf (latlon, "%d-%d-%d", °, &min, &sec); |
107 | } |
108 | if (deg > 180 || min >= 60 || sec >= 60) |
109 | return DBL_MAX1.7976931348623157e+308; |
110 | value = (gdouble)((deg * 60 + min) * 60 + sec) * M_PI3.14159265358979323846 / 648000.; |
111 | |
112 | dir = g_ascii_toupper (latlon[strlen (latlon) - 1]); |
113 | if (dir == 'W' || dir == 'S') |
114 | value = -value; |
115 | else if (dir != 'E' && dir != 'N' && (value != 0.0 || dir != '0')) |
116 | value = DBL_MAX1.7976931348623157e+308; |
117 | return value; |
118 | } |
119 | |
120 | WeatherLocation * |
121 | weather_location_new (const gchar *name, const gchar *code, |
122 | const gchar *zone, const gchar *radar, |
123 | const gchar *coordinates, |
124 | const gchar *country_code, |
125 | const gchar *tz_hint) |
126 | { |
127 | WeatherLocation *location; |
128 | |
129 | _weather_internal_check (); |
130 | |
131 | location = g_new (WeatherLocation, 1)(WeatherLocation *) (__extension__ ({ gsize __n = (gsize) (1) ; gsize __s = sizeof (WeatherLocation); gpointer __p; if (__s == 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n ) && (__s == 0 || __n <= (9223372036854775807L *2UL +1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s); __p; })); |
132 | |
133 | /* name and metar code must be set */ |
134 | location->name = g_strdup (name); |
135 | location->code = g_strdup (code); |
136 | |
137 | if (zone) { |
138 | location->zone = g_strdup (zone); |
139 | } else { |
140 | location->zone = g_strdup ("------"); |
141 | } |
142 | |
143 | if (radar) { |
144 | location->radar = g_strdup (radar); |
145 | } else { |
146 | location->radar = g_strdup ("---"); |
147 | } |
148 | |
149 | if (location->zone[0] == '-') { |
150 | location->zone_valid = FALSE(0); |
151 | } else { |
152 | location->zone_valid = TRUE(!(0)); |
153 | } |
154 | |
155 | location->coordinates = NULL((void*)0); |
156 | if (coordinates) |
157 | { |
158 | char **pieces; |
159 | |
160 | pieces = g_strsplit (coordinates, " ", -1); |
161 | |
162 | if (g_strv_length (pieces) == 2) |
163 | { |
164 | location->coordinates = g_strdup (coordinates); |
165 | location->latitude = dmsh2rad (pieces[0]); |
166 | location->longitude = dmsh2rad (pieces[1]); |
167 | } |
168 | |
169 | g_strfreev (pieces); |
170 | } |
171 | |
172 | if (!location->coordinates) |
173 | { |
174 | location->coordinates = g_strdup ("---"); |
175 | location->latitude = DBL_MAX1.7976931348623157e+308; |
176 | location->longitude = DBL_MAX1.7976931348623157e+308; |
177 | } |
178 | |
179 | location->latlon_valid = (location->latitude < DBL_MAX1.7976931348623157e+308 && location->longitude < DBL_MAX1.7976931348623157e+308); |
180 | |
181 | location->country_code = g_strdup (country_code); |
182 | location->tz_hint = g_strdup (tz_hint); |
183 | |
184 | return location; |
185 | } |
186 | |
187 | WeatherLocation * |
188 | weather_location_clone (const WeatherLocation *location) |
189 | { |
190 | WeatherLocation *clone; |
191 | |
192 | g_return_val_if_fail (location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "location != NULL" ); return (((void*)0)); } } while (0); |
193 | |
194 | clone = weather_location_new (location->name, |
195 | location->code, location->zone, |
196 | location->radar, location->coordinates, |
197 | location->country_code, location->tz_hint); |
198 | clone->latitude = location->latitude; |
199 | clone->longitude = location->longitude; |
200 | clone->latlon_valid = location->latlon_valid; |
201 | return clone; |
202 | } |
203 | |
204 | void |
205 | weather_location_free (WeatherLocation *location) |
206 | { |
207 | if (location) { |
208 | g_free (location->name); |
209 | g_free (location->code); |
210 | g_free (location->zone); |
211 | g_free (location->radar); |
212 | g_free (location->coordinates); |
213 | g_free (location->country_code); |
214 | g_free (location->tz_hint); |
215 | |
216 | g_free (location); |
217 | } |
218 | } |
219 | |
220 | gboolean |
221 | weather_location_equal (const WeatherLocation *location1, const WeatherLocation *location2) |
222 | { |
223 | /* if something is NULL, then it's TRUE if and only if both are NULL) */ |
224 | if (location1 == NULL((void*)0) || location2 == NULL((void*)0)) |
225 | return (location1 == location2); |
226 | if (!location1->code || !location2->code) |
227 | return (location1->code == location2->code); |
228 | if (!location1->name || !location2->name) |
229 | return (location1->name == location2->name); |
230 | |
231 | return ((strcmp (location1->code, location2->code) == 0) && |
232 | (strcmp (location1->name, location2->name) == 0)); |
233 | } |
234 | |
235 | static const gchar *wind_direction_str[] = { |
236 | N_("Variable")("Variable"), |
237 | N_("North")("North"), N_("North - NorthEast")("North - NorthEast"), N_("Northeast")("Northeast"), N_("East - NorthEast")("East - NorthEast"), |
238 | N_("East")("East"), N_("East - Southeast")("East - Southeast"), N_("Southeast")("Southeast"), N_("South - Southeast")("South - Southeast"), |
239 | N_("South")("South"), N_("South - Southwest")("South - Southwest"), N_("Southwest")("Southwest"), N_("West - Southwest")("West - Southwest"), |
240 | N_("West")("West"), N_("West - Northwest")("West - Northwest"), N_("Northwest")("Northwest"), N_("North - Northwest")("North - Northwest") |
241 | }; |
242 | |
243 | const gchar * |
244 | weather_wind_direction_string (WeatherWindDirection wind) |
245 | { |
246 | if (wind <= WIND_INVALID || wind >= WIND_LAST) |
247 | return _("Invalid")(mateweather_gettext ("Invalid")); |
248 | |
249 | return _(wind_direction_str[(int)wind])(mateweather_gettext (wind_direction_str[(int)wind])); |
250 | } |
251 | |
252 | static const gchar *sky_str[] = { |
253 | N_("Clear Sky")("Clear Sky"), |
254 | N_("Broken clouds")("Broken clouds"), |
255 | N_("Scattered clouds")("Scattered clouds"), |
256 | N_("Few clouds")("Few clouds"), |
257 | N_("Overcast")("Overcast") |
258 | }; |
259 | |
260 | const gchar * |
261 | weather_sky_string (WeatherSky sky) |
262 | { |
263 | if (sky <= SKY_INVALID || sky >= SKY_LAST) |
264 | return _("Invalid")(mateweather_gettext ("Invalid")); |
265 | |
266 | return _(sky_str[(int)sky])(mateweather_gettext (sky_str[(int)sky])); |
267 | } |
268 | |
269 | /* |
270 | * Even though tedious, I switched to a 2D array for weather condition |
271 | * strings, in order to facilitate internationalization, esp. for languages |
272 | * with genders. |
273 | */ |
274 | |
275 | /* |
276 | * Almost all reportable combinations listed in |
277 | * http://www.crh.noaa.gov/arx/wx.tbl.php are entered below, except those |
278 | * having 2 qualifiers mixed together [such as "Blowing snow in vicinity" |
279 | * (VCBLSN), "Thunderstorm in vicinity" (VCTS), etc]. |
280 | * Combinations that are not possible are filled in with "??". |
281 | * Some other exceptions not handled yet, such as "SN BLSN" which has |
282 | * special meaning. |
283 | */ |
284 | |
285 | /* |
286 | * Note, magic numbers, when you change the size here, make sure to change |
287 | * the below function so that new values are recognized |
288 | */ |
289 | /* NONE VICINITY LIGHT MODERATE HEAVY SHALLOW PATCHES PARTIAL THUNDERSTORM BLOWING SHOWERS DRIFTING FREEZING */ |
290 | /* *******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ |
291 | static const gchar *conditions_str[24][13] = { |
292 | /* Translators: If you want to know what "blowing" "shallow" "partial" |
293 | * etc means, you can go to http://www.weather.com/glossary/ and |
294 | * http://www.crh.noaa.gov/arx/wx.tbl.php */ |
295 | /* NONE */ {"??", "??", "??", "??", "??", "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", "??", "??", "??" }, |
296 | /* DRIZZLE */ {N_("Drizzle")("Drizzle"), "??", N_("Light drizzle")("Light drizzle"), N_("Moderate drizzle")("Moderate drizzle"), N_("Heavy drizzle")("Heavy drizzle"), "??", "??", "??", "??", "??", "??", "??", N_("Freezing drizzle")("Freezing drizzle") }, |
297 | /* RAIN */ {N_("Rain")("Rain"), "??", N_("Light rain")("Light rain"), N_("Moderate rain")("Moderate rain"), N_("Heavy rain")("Heavy rain"), "??", "??", "??", N_("Thunderstorm")("Thunderstorm"), "??", N_("Rain showers")("Rain showers"), "??", N_("Freezing rain")("Freezing rain") }, |
298 | /* SNOW */ {N_("Snow")("Snow"), "??", N_("Light snow")("Light snow"), N_("Moderate snow")("Moderate snow"), N_("Heavy snow")("Heavy snow"), "??", "??", "??", N_("Snowstorm")("Snowstorm"), N_("Blowing snowfall")("Blowing snowfall"), N_("Snow showers")("Snow showers"), N_("Drifting snow")("Drifting snow"), "??" }, |
299 | /* SNOW_GRAINS */ {N_("Snow grains")("Snow grains"), "??", N_("Light snow grains")("Light snow grains"), N_("Moderate snow grains")("Moderate snow grains"), N_("Heavy snow grains")("Heavy snow grains"), "??", "??", "??", "??", "??", "??", "??", "??" }, |
300 | /* ICE_CRYSTALS */ {N_("Ice crystals")("Ice crystals"), "??", "??", N_("Ice crystals")("Ice crystals"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
301 | /* ICE_PELLETS */ {N_("Ice pellets")("Ice pellets"), "??", N_("Few ice pellets")("Few ice pellets"), N_("Moderate ice pellets")("Moderate ice pellets"), N_("Heavy ice pellets")("Heavy ice pellets"), "??", "??", "??", N_("Ice pellet storm")("Ice pellet storm"), "??", N_("Showers of ice pellets")("Showers of ice pellets"), "??", "??" }, |
302 | /* HAIL */ {N_("Hail")("Hail"), "??", "??", N_("Hail")("Hail"), "??", "??", "??", "??", N_("Hailstorm")("Hailstorm"), "??", N_("Hail showers")("Hail showers"), "??", "??", }, |
303 | /* SMALL_HAIL */ {N_("Small hail")("Small hail"), "??", "??", N_("Small hail")("Small hail"), "??", "??", "??", "??", N_("Small hailstorm")("Small hailstorm"), "??", N_("Showers of small hail")("Showers of small hail"), "??", "??" }, |
304 | /* PRECIPITATION */ {N_("Unknown precipitation")("Unknown precipitation"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
305 | /* MIST */ {N_("Mist")("Mist"), "??", "??", N_("Mist")("Mist"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
306 | /* FOG */ {N_("Fog")("Fog"), N_("Fog in the vicinity")("Fog in the vicinity") , "??", N_("Fog")("Fog"), "??", N_("Shallow fog")("Shallow fog"), N_("Patches of fog")("Patches of fog"), N_("Partial fog")("Partial fog"), "??", "??", "??", "??", N_("Freezing fog")("Freezing fog") }, |
307 | /* SMOKE */ {N_("Smoke")("Smoke"), "??", "??", N_("Smoke")("Smoke"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
308 | /* VOLCANIC_ASH */ {N_("Volcanic ash")("Volcanic ash"), "??", "??", N_("Volcanic ash")("Volcanic ash"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
309 | /* SAND */ {N_("Sand")("Sand"), "??", "??", N_("Sand")("Sand"), "??", "??", "??", "??", "??", N_("Blowing sand")("Blowing sand"), "", N_("Drifting sand")("Drifting sand"), "??" }, |
310 | /* HAZE */ {N_("Haze")("Haze"), "??", "??", N_("Haze")("Haze"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
311 | /* SPRAY */ {"??", "??", "??", "??", "??", "??", "??", "??", "??", N_("Blowing sprays")("Blowing sprays"), "??", "??", "??" }, |
312 | /* DUST */ {N_("Dust")("Dust"), "??", "??", N_("Dust")("Dust"), "??", "??", "??", "??", "??", N_("Blowing dust")("Blowing dust"), "??", N_("Drifting dust")("Drifting dust"), "??" }, |
313 | /* SQUALL */ {N_("Squall")("Squall"), "??", "??", N_("Squall")("Squall"), "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
314 | /* SANDSTORM */ {N_("Sandstorm")("Sandstorm"), N_("Sandstorm in the vicinity")("Sandstorm in the vicinity") , "??", N_("Sandstorm")("Sandstorm"), N_("Heavy sandstorm")("Heavy sandstorm"), "??", "??", "??", "??", "??", "??", "??", "??" }, |
315 | /* DUSTSTORM */ {N_("Duststorm")("Duststorm"), N_("Duststorm in the vicinity")("Duststorm in the vicinity") , "??", N_("Duststorm")("Duststorm"), N_("Heavy duststorm")("Heavy duststorm"), "??", "??", "??", "??", "??", "??", "??", "??" }, |
316 | /* FUNNEL_CLOUD */ {N_("Funnel cloud")("Funnel cloud"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
317 | /* TORNADO */ {N_("Tornado")("Tornado"), "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??" }, |
318 | /* DUST_WHIRLS */ {N_("Dust whirls")("Dust whirls"), N_("Dust whirls in the vicinity")("Dust whirls in the vicinity") , "??", N_("Dust whirls")("Dust whirls"), "??", "??", "??", "??", "??", "??", "??", "??", "??" } |
319 | }; |
320 | |
321 | const gchar * |
322 | weather_conditions_string (WeatherConditions cond) |
323 | { |
324 | const gchar *str; |
325 | |
326 | if (!cond.significant) { |
327 | return "-"; |
328 | } else { |
329 | if (cond.phenomenon > PHENOMENON_INVALID && |
330 | cond.phenomenon < PHENOMENON_LAST && |
331 | cond.qualifier > QUALIFIER_INVALID && |
332 | cond.qualifier < QUALIFIER_LAST) |
333 | str = _(conditions_str[(int)cond.phenomenon][(int)cond.qualifier])(mateweather_gettext (conditions_str[(int)cond.phenomenon][(int )cond.qualifier])); |
334 | else |
335 | str = _("Invalid")(mateweather_gettext ("Invalid")); |
336 | return (strlen (str) > 0) ? str : "-"; |
337 | } |
338 | } |
339 | |
340 | /* Locals turned global to facilitate asynchronous HTTP requests */ |
341 | |
342 | gboolean |
343 | requests_init (WeatherInfo *info) |
344 | { |
345 | if (info->requests_pending) |
346 | return FALSE(0); |
347 | |
348 | return TRUE(!(0)); |
349 | } |
350 | |
351 | void request_done (WeatherInfo *info, gboolean ok) |
352 | { |
353 | if (ok) { |
354 | (void) calc_sun (info); |
355 | info->moonValid = info->valid && calc_moon (info); |
356 | } |
357 | if (!--info->requests_pending) |
358 | info->finish_cb (info, info->cb_data); |
359 | } |
360 | |
361 | /* it's OK to pass in NULL */ |
362 | void |
363 | free_forecast_list (WeatherInfo *info) |
364 | { |
365 | GSList *p; |
366 | |
367 | if (!info) |
368 | return; |
369 | |
370 | for (p = info->forecast_list; p; p = p->next) |
371 | weather_info_free (p->data); |
372 | |
373 | if (info->forecast_list) { |
374 | g_slist_free (info->forecast_list); |
375 | info->forecast_list = NULL((void*)0); |
376 | } |
377 | } |
378 | |
379 | /* Relative humidity computation - thanks to <Olof.Oberg@modopaper.modogroup.com> */ |
380 | |
381 | static inline gdouble |
382 | calc_humidity (gdouble temp, gdouble dewp) |
383 | { |
384 | gdouble esat, esurf; |
385 | |
386 | if (temp > -500.0 && dewp > -500.0) { |
387 | temp = TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0)); |
388 | dewp = TEMP_F_TO_C (dewp)(((dewp) - 32.0) * (5.0/9.0)); |
389 | |
390 | esat = 6.11 * pow (10.0, (7.5 * temp) / (237.7 + temp)); |
391 | esurf = 6.11 * pow (10.0, (7.5 * dewp) / (237.7 + dewp)); |
392 | } else { |
393 | esurf = -1.0; |
394 | esat = 1.0; |
395 | } |
396 | return ((esurf/esat) * 100.0); |
397 | } |
398 | |
399 | static inline gdouble |
400 | calc_apparent (WeatherInfo *info) |
401 | { |
402 | gdouble temp = info->temp; |
403 | gdouble wind = WINDSPEED_KNOTS_TO_MPH (info->windspeed)((info->windspeed) * 1.150779); |
404 | gdouble apparent = -1000.; |
405 | |
406 | /* |
407 | * Wind chill calculations as of 01-Nov-2001 |
408 | * http://www.nws.noaa.gov/om/windchill/index.shtml |
409 | * Some pages suggest that the formula will soon be adjusted |
410 | * to account for solar radiation (bright sun vs cloudy sky) |
411 | */ |
412 | if (temp <= 50.0) { |
413 | if (wind > 3.0) { |
414 | gdouble v = pow (wind, 0.16); |
415 | apparent = 35.74 + 0.6215 * temp - 35.75 * v + 0.4275 * temp * v; |
416 | } else if (wind >= 0.) { |
417 | apparent = temp; |
418 | } |
419 | } |
420 | /* |
421 | * Heat index calculations: |
422 | * http://www.srh.noaa.gov/fwd/heatindex/heat5.html |
423 | */ |
424 | else if (temp >= 80.0) { |
425 | if (info->temp >= -500. && info->dew >= -500.) { |
426 | gdouble humidity = calc_humidity (info->temp, info->dew); |
427 | gdouble t2 = temp * temp; |
428 | gdouble h2 = humidity * humidity; |
429 | |
430 | #if 1 |
431 | /* |
432 | * A really precise formula. Note that overall precision is |
433 | * constrained by the accuracy of the instruments and that the |
434 | * we receive the temperature and dewpoints as integers. |
435 | */ |
436 | gdouble t3 = t2 * temp; |
437 | gdouble h3 = h2 * temp; |
438 | |
439 | apparent = 16.923 |
440 | + 0.185212 * temp |
441 | + 5.37941 * humidity |
442 | - 0.100254 * temp * humidity |
443 | + 9.41695e-3 * t2 |
444 | + 7.28898e-3 * h2 |
445 | + 3.45372e-4 * t2 * humidity |
446 | - 8.14971e-4 * temp * h2 |
447 | + 1.02102e-5 * t2 * h2 |
448 | - 3.8646e-5 * t3 |
449 | + 2.91583e-5 * h3 |
450 | + 1.42721e-6 * t3 * humidity |
451 | + 1.97483e-7 * temp * h3 |
452 | - 2.18429e-8 * t3 * h2 |
453 | + 8.43296e-10 * t2 * h3 |
454 | - 4.81975e-11 * t3 * h3; |
455 | #else |
456 | /* |
457 | * An often cited alternative: values are within 5 degrees for |
458 | * most ranges between 10% and 70% humidity and to 110 degrees. |
459 | */ |
460 | apparent = - 42.379 |
461 | + 2.04901523 * temp |
462 | + 10.14333127 * humidity |
463 | - 0.22475541 * temp * humidity |
464 | - 6.83783e-3 * t2 |
465 | - 5.481717e-2 * h2 |
466 | + 1.22874e-3 * t2 * humidity |
467 | + 8.5282e-4 * temp * h2 |
468 | - 1.99e-6 * t2 * h2; |
469 | #endif |
470 | } |
471 | } else { |
472 | apparent = temp; |
473 | } |
474 | |
475 | return apparent; |
476 | } |
477 | |
478 | WeatherInfo * |
479 | _weather_info_fill (WeatherInfo *info, |
480 | WeatherLocation *location, |
481 | const WeatherPrefs *prefs, |
482 | WeatherInfoFunc cb, |
483 | gpointer data) |
484 | { |
485 | g_return_val_if_fail (((info == NULL) && (location != NULL)) || \do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (((info == ((void*)0)) && (location != ((void*)0 ))) || ((info != ((void*)0)) && (location == ((void*) 0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 1))) { } else { g_return_if_fail_warning ("MateWeather" , ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))" ); return (((void*)0)); } } while (0) |
486 | ((info != NULL) && (location == NULL)), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (((info == ((void*)0)) && (location != ((void*)0 ))) || ((info != ((void*)0)) && (location == ((void*) 0)))) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 1))) { } else { g_return_if_fail_warning ("MateWeather" , ((const char*) (__func__)), "((info == NULL) && (location != NULL)) || ((info != NULL) && (location == NULL))" ); return (((void*)0)); } } while (0); |
487 | g_return_val_if_fail (prefs != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (prefs != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "prefs != NULL") ; return (((void*)0)); } } while (0); |
488 | |
489 | /* FIXME: i'm not sure this works as intended anymore */ |
490 | if (!info) { |
491 | info = g_new0 (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize __s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p = g_malloc0 (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s )) __p = g_malloc0 (__n * __s); else __p = g_malloc0_n (__n, __s ); __p; })); |
492 | info->requests_pending = 0; |
493 | info->location = weather_location_clone (location); |
494 | } else { |
495 | location = info->location; |
496 | if (info->forecast) |
497 | g_free (info->forecast); |
498 | info->forecast = NULL((void*)0); |
499 | |
500 | free_forecast_list (info); |
501 | |
502 | if (info->radar != NULL((void*)0)) { |
503 | g_object_unref (info->radar); |
504 | info->radar = NULL((void*)0); |
505 | } |
506 | } |
507 | |
508 | /* Update in progress */ |
509 | if (!requests_init (info)) { |
510 | return NULL((void*)0); |
511 | } |
512 | |
513 | /* Defaults (just in case...) */ |
514 | /* Well, no just in case anymore. We may actually fail to fetch some |
515 | * fields. */ |
516 | info->forecast_type = prefs->type; |
517 | |
518 | info->temperature_unit = prefs->temperature_unit; |
519 | info->speed_unit = prefs->speed_unit; |
520 | info->pressure_unit = prefs->pressure_unit; |
521 | info->distance_unit = prefs->distance_unit; |
522 | |
523 | info->update = 0; |
524 | info->sky = -1; |
525 | info->cond.significant = FALSE(0); |
526 | info->cond.phenomenon = PHENOMENON_NONE; |
527 | info->cond.qualifier = QUALIFIER_NONE; |
528 | info->temp = -1000.0; |
529 | info->tempMinMaxValid = FALSE(0); |
530 | info->temp_min = -1000.0; |
531 | info->temp_max = -1000.0; |
532 | info->dew = -1000.0; |
533 | info->wind = -1; |
534 | info->windspeed = -1; |
535 | info->pressure = -1.0; |
536 | info->visibility = -1.0; |
537 | info->sunriseValid = FALSE(0); |
538 | info->sunsetValid = FALSE(0); |
539 | info->moonValid = FALSE(0); |
540 | info->sunrise = 0; |
541 | info->sunset = 0; |
542 | info->moonphase = 0; |
543 | info->moonlatitude = 0; |
544 | info->forecast = NULL((void*)0); |
545 | info->forecast_list = NULL((void*)0); |
546 | info->radar = NULL((void*)0); |
547 | info->radar_url = prefs->radar && prefs->radar_custom_url ? |
548 | g_strdup (prefs->radar_custom_url) : NULL((void*)0); |
549 | info->finish_cb = cb; |
550 | info->cb_data = data; |
551 | |
552 | if (!info->session) { |
553 | info->session = soup_session_new (); |
554 | } |
555 | |
556 | metar_start_open (info); |
557 | iwin_start_open (info); |
558 | |
559 | if (prefs->radar) { |
560 | wx_start_open (info); |
561 | } |
562 | |
563 | return info; |
564 | } |
565 | |
566 | void |
567 | weather_info_abort (WeatherInfo *info) |
568 | { |
569 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
570 | |
571 | if (info->session) { |
572 | soup_session_abort (info->session); |
573 | info->requests_pending = 0; |
574 | } |
575 | } |
576 | |
577 | WeatherInfo * |
578 | weather_info_clone (const WeatherInfo *info) |
579 | { |
580 | WeatherInfo *clone; |
581 | |
582 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
583 | |
584 | clone = g_new (WeatherInfo, 1)(WeatherInfo *) (__extension__ ({ gsize __n = (gsize) (1); gsize __s = sizeof (WeatherInfo); gpointer __p; if (__s == 1) __p = g_malloc (__n); else if (__builtin_constant_p (__n) && (__s == 0 || __n <= (9223372036854775807L *2UL+1UL) / __s )) __p = g_malloc (__n * __s); else __p = g_malloc_n (__n, __s ); __p; })); |
585 | |
586 | /* move everything */ |
587 | memmove (clone, info, sizeof (WeatherInfo)); |
588 | |
589 | /* special moves */ |
590 | clone->location = weather_location_clone (info->location); |
591 | /* This handles null correctly */ |
592 | clone->forecast = g_strdup (info->forecast); |
593 | clone->radar_url = g_strdup (info->radar_url); |
594 | |
595 | if (info->forecast_list) { |
596 | GSList *p; |
597 | |
598 | clone->forecast_list = NULL((void*)0); |
599 | for (p = info->forecast_list; p; p = p->next) { |
600 | clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data)); |
601 | } |
602 | |
603 | clone->forecast_list = g_slist_reverse (clone->forecast_list); |
604 | } |
605 | |
606 | clone->radar = info->radar; |
607 | if (clone->radar != NULL((void*)0)) |
608 | g_object_ref (clone->radar)((__typeof__ (clone->radar)) (g_object_ref) (clone->radar )); |
609 | |
610 | return clone; |
611 | } |
612 | |
613 | void |
614 | weather_info_free (WeatherInfo *info) |
615 | { |
616 | if (!info) |
617 | return; |
618 | |
619 | weather_info_abort (info); |
620 | if (info->session) |
621 | g_object_unref (info->session); |
622 | |
623 | weather_location_free (info->location); |
624 | info->location = NULL((void*)0); |
625 | |
626 | g_free (info->forecast); |
627 | info->forecast = NULL((void*)0); |
628 | |
629 | free_forecast_list (info); |
630 | |
631 | if (info->radar != NULL((void*)0)) { |
632 | g_object_unref (info->radar); |
633 | info->radar = NULL((void*)0); |
634 | } |
635 | |
636 | g_free (info); |
637 | } |
638 | |
639 | gboolean |
640 | weather_info_is_valid (WeatherInfo *info) |
641 | { |
642 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
643 | return info->valid; |
644 | } |
645 | |
646 | gboolean |
647 | weather_info_network_error (WeatherInfo *info) |
648 | { |
649 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
650 | return info->network_error; |
651 | } |
652 | |
653 | void |
654 | weather_info_to_metric (WeatherInfo *info) |
655 | { |
656 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
657 | |
658 | info->temperature_unit = TEMP_UNIT_CENTIGRADE; |
659 | info->speed_unit = SPEED_UNIT_MS; |
660 | info->pressure_unit = PRESSURE_UNIT_HPA; |
661 | info->distance_unit = DISTANCE_UNIT_METERS; |
662 | } |
663 | |
664 | void |
665 | weather_info_to_imperial (WeatherInfo *info) |
666 | { |
667 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
668 | |
669 | info->temperature_unit = TEMP_UNIT_FAHRENHEIT; |
670 | info->speed_unit = SPEED_UNIT_MPH; |
671 | info->pressure_unit = PRESSURE_UNIT_INCH_HG; |
672 | info->distance_unit = DISTANCE_UNIT_MILES; |
673 | } |
674 | |
675 | const WeatherLocation * |
676 | weather_info_get_location (WeatherInfo *info) |
677 | { |
678 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
679 | return info->location; |
680 | } |
681 | |
682 | const gchar * |
683 | weather_info_get_location_name (WeatherInfo *info) |
684 | { |
685 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
686 | g_return_val_if_fail (info->location != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info->location != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info->location != NULL" ); return (((void*)0)); } } while (0); |
687 | return info->location->name; |
688 | } |
689 | |
690 | const gchar * |
691 | weather_info_get_update (WeatherInfo *info) |
692 | { |
693 | static gchar buf[200]; |
694 | char *utf8, *timeformat; |
695 | |
696 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
697 | |
698 | if (!info->valid) |
699 | return "-"; |
700 | |
701 | if (info->update != 0) { |
702 | struct tm tm; |
703 | localtime_r (&info->update, &tm); |
704 | /* Translators: this is a format string for strftime |
705 | * see `man 3 strftime` for more details |
706 | */ |
707 | timeformat = g_locale_from_utf8 (_("%a, %b %d / %H:%M")(mateweather_gettext ("%a, %b %d / %H:%M")), -1, |
708 | NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
709 | if (!timeformat) { |
710 | strcpy (buf, "???"); |
711 | } |
712 | else if (strftime (buf, sizeof (buf), timeformat, &tm) <= 0) { |
713 | strcpy (buf, "???"); |
714 | } |
715 | g_free (timeformat); |
716 | |
717 | /* Convert to UTF-8 */ |
718 | utf8 = g_locale_to_utf8 (buf, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
719 | strcpy (buf, utf8); |
Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119 | |
720 | g_free (utf8); |
721 | } else { |
722 | strncpy (buf, _("Unknown observation time")(mateweather_gettext ("Unknown observation time")), sizeof (buf)); |
723 | buf[sizeof (buf)-1] = '\0'; |
724 | } |
725 | |
726 | return buf; |
727 | } |
728 | |
729 | const gchar * |
730 | weather_info_get_sky (WeatherInfo *info) |
731 | { |
732 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
733 | if (!info->valid) |
734 | return "-"; |
735 | if (info->sky < 0) |
736 | return _("Unknown")(mateweather_gettext ("Unknown")); |
737 | return weather_sky_string (info->sky); |
738 | } |
739 | |
740 | const gchar * |
741 | weather_info_get_conditions (WeatherInfo *info) |
742 | { |
743 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
744 | if (!info->valid) |
745 | return "-"; |
746 | return weather_conditions_string (info->cond); |
747 | } |
748 | |
749 | static const gchar * |
750 | temperature_string (gdouble temp, TempUnit to_unit, gboolean want_round) |
751 | { |
752 | static gchar buf[100]; |
753 | |
754 | switch (to_unit) { |
755 | case TEMP_UNIT_FAHRENHEIT: |
756 | if (!want_round) { |
757 | /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */ |
758 | g_snprintf (buf, sizeof (buf), _("%.1f \302\260F")(mateweather_gettext ("%.1f \302\260F")), temp); |
759 | } else { |
760 | const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10; |
761 | gdouble temp_r; |
762 | |
763 | feclearexcept(range_problem); |
764 | temp_r = round (temp); |
765 | if (fetestexcept(range_problem)) |
766 | g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a"))); |
767 | else |
768 | /* Translators: This is the temperature in degrees Fahrenheit (\302\260 is U+00B0 DEGREE SIGN) */ |
769 | g_snprintf (buf, sizeof (buf), _("%d \302\260F")(mateweather_gettext ("%d \302\260F")), (int)temp_r); |
770 | } |
771 | break; |
772 | case TEMP_UNIT_CENTIGRADE: |
773 | if (!want_round) { |
774 | /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */ |
775 | g_snprintf (buf, sizeof (buf), _("%.1f \302\260C")(mateweather_gettext ("%.1f \302\260C")), TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0))); |
776 | } else { |
777 | const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10; |
778 | gdouble temp_r; |
779 | |
780 | feclearexcept(range_problem); |
781 | temp_r = round (TEMP_F_TO_C (temp)(((temp) - 32.0) * (5.0/9.0))); |
782 | if (fetestexcept(range_problem)) |
783 | g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a"))); |
784 | else |
785 | /* Translators: This is the temperature in degrees Celsius (\302\260 is U+00B0 DEGREE SIGN) */ |
786 | g_snprintf (buf, sizeof (buf), _("%d \302\260C")(mateweather_gettext ("%d \302\260C")), (int)temp_r); |
787 | } |
788 | break; |
789 | case TEMP_UNIT_KELVIN: |
790 | if (!want_round) { |
791 | /* Translators: This is the temperature in kelvin */ |
792 | g_snprintf (buf, sizeof (buf), _("%.1f K")(mateweather_gettext ("%.1f K")), TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0))); |
793 | } else { |
794 | const int range_problem = FE_INVALID0x01 | FE_DIVBYZERO0x04 | FE_OVERFLOW0x08 | FE_UNDERFLOW0x10; |
795 | gdouble temp_r; |
796 | |
797 | feclearexcept(range_problem); |
798 | temp_r = round (TEMP_F_TO_K (temp)((temp + 459.67) * (5.0/9.0))); |
799 | if (fetestexcept(range_problem)) |
800 | g_snprintf (buf, sizeof (buf), _("n/a")(mateweather_gettext ("n/a"))); |
801 | else |
802 | /* Translators: This is the temperature in kelvin */ |
803 | g_snprintf (buf, sizeof (buf), _("%d K")(mateweather_gettext ("%d K")), (int)temp_r); |
804 | } |
805 | break; |
806 | |
807 | case TEMP_UNIT_INVALID: |
808 | case TEMP_UNIT_DEFAULT: |
809 | default: |
810 | g_warning ("Conversion to illegal temperature unit: %d", to_unit); |
811 | return _("Unknown")(mateweather_gettext ("Unknown")); |
812 | } |
813 | |
814 | return buf; |
815 | } |
816 | |
817 | const gchar * |
818 | weather_info_get_temp (WeatherInfo *info) |
819 | { |
820 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
821 | |
822 | if (!info->valid) |
823 | return "-"; |
824 | if (info->temp < -500.0) |
825 | return _("Unknown")(mateweather_gettext ("Unknown")); |
826 | |
827 | return temperature_string (info->temp, info->temperature_unit, FALSE(0)); |
828 | } |
829 | |
830 | const gchar * |
831 | weather_info_get_temp_min (WeatherInfo *info) |
832 | { |
833 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
834 | |
835 | if (!info->valid || !info->tempMinMaxValid) |
836 | return "-"; |
837 | if (info->temp_min < -500.0) |
838 | return _("Unknown")(mateweather_gettext ("Unknown")); |
839 | |
840 | return temperature_string (info->temp_min, info->temperature_unit, FALSE(0)); |
841 | } |
842 | |
843 | const gchar * |
844 | weather_info_get_temp_max (WeatherInfo *info) |
845 | { |
846 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
847 | |
848 | if (!info->valid || !info->tempMinMaxValid) |
849 | return "-"; |
850 | if (info->temp_max < -500.0) |
851 | return _("Unknown")(mateweather_gettext ("Unknown")); |
852 | |
853 | return temperature_string (info->temp_max, info->temperature_unit, FALSE(0)); |
854 | } |
855 | |
856 | const gchar * |
857 | weather_info_get_dew (WeatherInfo *info) |
858 | { |
859 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
860 | |
861 | if (!info->valid) |
862 | return "-"; |
863 | if (info->dew < -500.0) |
864 | return _("Unknown")(mateweather_gettext ("Unknown")); |
865 | |
866 | return temperature_string (info->dew, info->temperature_unit, FALSE(0)); |
867 | } |
868 | |
869 | const gchar * |
870 | weather_info_get_humidity (WeatherInfo *info) |
871 | { |
872 | static gchar buf[20]; |
873 | gdouble humidity; |
874 | |
875 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
876 | |
877 | if (!info->valid) |
878 | return "-"; |
879 | |
880 | humidity = calc_humidity (info->temp, info->dew); |
881 | if (humidity < 0.0) |
882 | return _("Unknown")(mateweather_gettext ("Unknown")); |
883 | |
884 | /* Translators: This is the humidity in percent */ |
885 | g_snprintf (buf, sizeof (buf), _("%.f%%")(mateweather_gettext ("%.f%%")), humidity); |
886 | return buf; |
887 | } |
888 | |
889 | const gchar * |
890 | weather_info_get_apparent (WeatherInfo *info) |
891 | { |
892 | gdouble apparent; |
893 | |
894 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
895 | if (!info->valid) |
896 | return "-"; |
897 | |
898 | apparent = calc_apparent (info); |
899 | if (apparent < -500.0) |
900 | return _("Unknown")(mateweather_gettext ("Unknown")); |
901 | |
902 | return temperature_string (apparent, info->temperature_unit, FALSE(0)); |
903 | } |
904 | |
905 | static const gchar * |
906 | windspeed_string (gfloat knots, SpeedUnit to_unit) |
907 | { |
908 | static gchar buf[100]; |
909 | |
910 | switch (to_unit) { |
911 | case SPEED_UNIT_KNOTS: |
912 | /* Translators: This is the wind speed in knots */ |
913 | g_snprintf (buf, sizeof (buf), _("%0.1f knots")(mateweather_gettext ("%0.1f knots")), knots); |
914 | break; |
915 | case SPEED_UNIT_MPH: |
916 | /* Translators: This is the wind speed in miles per hour */ |
917 | g_snprintf (buf, sizeof (buf), _("%.1f mph")(mateweather_gettext ("%.1f mph")), WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779)); |
918 | break; |
919 | case SPEED_UNIT_KPH: |
920 | /* Translators: This is the wind speed in kilometers per hour */ |
921 | g_snprintf (buf, sizeof (buf), _("%.1f km/h")(mateweather_gettext ("%.1f km/h")), WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965)); |
922 | break; |
923 | case SPEED_UNIT_MS: |
924 | /* Translators: This is the wind speed in meters per second */ |
925 | g_snprintf (buf, sizeof (buf), _("%.1f m/s")(mateweather_gettext ("%.1f m/s")), WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444)); |
926 | break; |
927 | case SPEED_UNIT_BFT: |
928 | /* Translators: This is the wind speed as a Beaufort force factor |
929 | * (commonly used in nautical wind estimation). |
930 | */ |
931 | g_snprintf (buf, sizeof (buf), _("Beaufort force %.1f")(mateweather_gettext ("Beaufort force %.1f")), |
932 | WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666))); |
933 | break; |
934 | case SPEED_UNIT_INVALID: |
935 | case SPEED_UNIT_DEFAULT: |
936 | default: |
937 | g_warning ("Conversion to illegal speed unit: %d", to_unit); |
938 | return _("Unknown")(mateweather_gettext ("Unknown")); |
939 | } |
940 | |
941 | return buf; |
942 | } |
943 | |
944 | const gchar * |
945 | weather_info_get_wind (WeatherInfo *info) |
946 | { |
947 | static gchar buf[200]; |
948 | |
949 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
950 | |
951 | if (!info->valid) |
952 | return "-"; |
953 | if (info->windspeed < 0.0 || info->wind < 0) |
954 | return _("Unknown")(mateweather_gettext ("Unknown")); |
955 | if (info->windspeed == 0.00) { |
956 | strncpy (buf, _("Calm")(mateweather_gettext ("Calm")), sizeof (buf)); |
957 | buf[sizeof (buf)-1] = '\0'; |
958 | } else { |
959 | /* Translators: This is 'wind direction' / 'wind speed' */ |
960 | g_snprintf (buf, sizeof (buf), _("%s / %s")(mateweather_gettext ("%s / %s")), |
961 | weather_wind_direction_string (info->wind), |
962 | windspeed_string (info->windspeed, info->speed_unit)); |
963 | } |
964 | return buf; |
965 | } |
966 | |
967 | const gchar * |
968 | weather_info_get_pressure (WeatherInfo *info) |
969 | { |
970 | static gchar buf[100]; |
971 | |
972 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
973 | |
974 | if (!info->valid) |
975 | return "-"; |
976 | if (info->pressure < 0.0) |
977 | return _("Unknown")(mateweather_gettext ("Unknown")); |
978 | |
979 | switch (info->pressure_unit) { |
980 | case PRESSURE_UNIT_INCH_HG: |
981 | /* Translators: This is pressure in inches of mercury */ |
982 | g_snprintf (buf, sizeof (buf), _("%.2f inHg")(mateweather_gettext ("%.2f inHg")), info->pressure); |
983 | break; |
984 | case PRESSURE_UNIT_MM_HG: |
985 | /* Translators: This is pressure in millimeters of mercury */ |
986 | g_snprintf (buf, sizeof (buf), _("%.1f mmHg")(mateweather_gettext ("%.1f mmHg")), PRESSURE_INCH_TO_MM (info->pressure)((info->pressure) * 25.40005)); |
987 | break; |
988 | case PRESSURE_UNIT_KPA: |
989 | /* Translators: This is pressure in kiloPascals */ |
990 | g_snprintf (buf, sizeof (buf), _("%.2f kPa")(mateweather_gettext ("%.2f kPa")), PRESSURE_INCH_TO_KPA (info->pressure)((info->pressure) * 3.386)); |
991 | break; |
992 | case PRESSURE_UNIT_HPA: |
993 | /* Translators: This is pressure in hectoPascals */ |
994 | g_snprintf (buf, sizeof (buf), _("%.2f hPa")(mateweather_gettext ("%.2f hPa")), PRESSURE_INCH_TO_HPA (info->pressure)((info->pressure) * 33.86)); |
995 | break; |
996 | case PRESSURE_UNIT_MB: |
997 | /* Translators: This is pressure in millibars */ |
998 | g_snprintf (buf, sizeof (buf), _("%.2f mb")(mateweather_gettext ("%.2f mb")), PRESSURE_INCH_TO_MB (info->pressure)(((info->pressure) * 33.86))); |
999 | break; |
1000 | case PRESSURE_UNIT_ATM: |
1001 | /* Translators: This is pressure in atmospheres */ |
1002 | g_snprintf (buf, sizeof (buf), _("%.3f atm")(mateweather_gettext ("%.3f atm")), PRESSURE_INCH_TO_ATM (info->pressure)((info->pressure) * 0.033421052)); |
1003 | break; |
1004 | |
1005 | case PRESSURE_UNIT_INVALID: |
1006 | case PRESSURE_UNIT_DEFAULT: |
1007 | default: |
1008 | g_warning ("Conversion to illegal pressure unit: %d", info->pressure_unit); |
1009 | return _("Unknown")(mateweather_gettext ("Unknown")); |
1010 | } |
1011 | |
1012 | return buf; |
1013 | } |
1014 | |
1015 | const gchar * |
1016 | weather_info_get_visibility (WeatherInfo *info) |
1017 | { |
1018 | static gchar buf[100]; |
1019 | |
1020 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1021 | |
1022 | if (!info->valid) |
1023 | return "-"; |
1024 | if (info->visibility < 0.0) |
1025 | return _("Unknown")(mateweather_gettext ("Unknown")); |
1026 | |
1027 | switch (info->distance_unit) { |
1028 | case DISTANCE_UNIT_MILES: |
1029 | /* Translators: This is the visibility in miles */ |
1030 | g_snprintf (buf, sizeof (buf), _("%.1f miles")(mateweather_gettext ("%.1f miles")), info->visibility); |
1031 | break; |
1032 | case DISTANCE_UNIT_KM: |
1033 | /* Translators: This is the visibility in kilometers */ |
1034 | g_snprintf (buf, sizeof (buf), _("%.1f km")(mateweather_gettext ("%.1f km")), VISIBILITY_SM_TO_KM (info->visibility)((info->visibility) * 1.609344)); |
1035 | break; |
1036 | case DISTANCE_UNIT_METERS: |
1037 | /* Translators: This is the visibility in meters */ |
1038 | g_snprintf (buf, sizeof (buf), _("%.0fm")(mateweather_gettext ("%.0fm")), VISIBILITY_SM_TO_M (info->visibility)(((info->visibility) * 1.609344) * 1000)); |
1039 | break; |
1040 | |
1041 | case DISTANCE_UNIT_INVALID: |
1042 | case DISTANCE_UNIT_DEFAULT: |
1043 | default: |
1044 | g_warning ("Conversion to illegal visibility unit: %d", info->pressure_unit); |
1045 | return _("Unknown")(mateweather_gettext ("Unknown")); |
1046 | } |
1047 | |
1048 | return buf; |
1049 | } |
1050 | |
1051 | const gchar * |
1052 | weather_info_get_sunrise (WeatherInfo *info) |
1053 | { |
1054 | static gchar buf[200]; |
1055 | struct tm tm; |
1056 | |
1057 | g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info && info->location) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__ )), "info && info->location"); return (((void*)0)) ; } } while (0); |
1058 | |
1059 | if (!info->location->latlon_valid) |
1060 | return "-"; |
1061 | if (!info->valid) |
1062 | return "-"; |
1063 | if (!calc_sun (info)) |
1064 | return "-"; |
1065 | |
1066 | localtime_r (&info->sunrise, &tm); |
1067 | if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0) |
1068 | return "-"; |
1069 | return buf; |
1070 | } |
1071 | |
1072 | const gchar * |
1073 | weather_info_get_sunset (WeatherInfo *info) |
1074 | { |
1075 | static gchar buf[200]; |
1076 | struct tm tm; |
1077 | |
1078 | g_return_val_if_fail (info && info->location, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info && info->location) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__ )), "info && info->location"); return (((void*)0)) ; } } while (0); |
1079 | |
1080 | if (!info->location->latlon_valid) |
1081 | return "-"; |
1082 | if (!info->valid) |
1083 | return "-"; |
1084 | if (!calc_sun (info)) |
1085 | return "-"; |
1086 | |
1087 | localtime_r (&info->sunset, &tm); |
1088 | if (strftime (buf, sizeof (buf), _("%H:%M")(mateweather_gettext ("%H:%M")), &tm) <= 0) |
1089 | return "-"; |
1090 | return buf; |
1091 | } |
1092 | |
1093 | const gchar * |
1094 | weather_info_get_forecast (WeatherInfo *info) |
1095 | { |
1096 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1097 | return info->forecast; |
1098 | } |
1099 | |
1100 | /** |
1101 | * weather_info_get_forecast_list: |
1102 | * Returns list of WeatherInfo* objects for the forecast. |
1103 | * The list is owned by the 'info' object thus is alive as long |
1104 | * as the 'info'. This list is filled only when requested with |
1105 | * type FORECAST_LIST and if available for given location. |
1106 | * The 'update' property is the date/time when the forecast info |
1107 | * is used for. |
1108 | **/ |
1109 | GSList * |
1110 | weather_info_get_forecast_list (WeatherInfo *info) |
1111 | { |
1112 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1113 | |
1114 | if (!info->valid) |
1115 | return NULL((void*)0); |
1116 | |
1117 | return info->forecast_list; |
1118 | } |
1119 | |
1120 | GdkPixbufAnimation * |
1121 | weather_info_get_radar (WeatherInfo *info) |
1122 | { |
1123 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1124 | return info->radar; |
1125 | } |
1126 | |
1127 | const gchar * |
1128 | weather_info_get_temp_summary (WeatherInfo *info) |
1129 | { |
1130 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1131 | |
1132 | if (!info->valid || info->temp < -500.0) |
1133 | return "--"; |
1134 | |
1135 | return temperature_string (info->temp, info->temperature_unit, TRUE(!(0))); |
1136 | |
1137 | } |
1138 | |
1139 | gchar * |
1140 | weather_info_get_weather_summary (WeatherInfo *info) |
1141 | { |
1142 | const gchar *buf; |
1143 | |
1144 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1145 | |
1146 | if (!info->valid) |
1147 | return g_strdup (_("Retrieval failed")(mateweather_gettext ("Retrieval failed"))); |
1148 | buf = weather_info_get_conditions (info); |
1149 | if (!strcmp (buf, "-")) |
1150 | buf = weather_info_get_sky (info); |
1151 | return g_strdup_printf ("%s: %s", weather_info_get_location_name (info), buf); |
1152 | } |
1153 | |
1154 | const gchar * |
1155 | weather_info_get_icon_name (WeatherInfo *info) |
1156 | { |
1157 | WeatherConditions cond; |
1158 | WeatherSky sky; |
1159 | time_t current_time; |
1160 | gboolean daytime; |
1161 | gchar* icon; |
1162 | static gchar icon_buffer[32]; |
1163 | WeatherMoonPhase moonPhase; |
1164 | WeatherMoonLatitude moonLat; |
1165 | gint phase; |
1166 | |
1167 | g_return_val_if_fail (info != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return (((void*)0)); } } while (0); |
1168 | |
1169 | if (!info->valid) |
1170 | return NULL((void*)0); |
1171 | |
1172 | cond = info->cond; |
1173 | sky = info->sky; |
1174 | |
1175 | if (cond.significant) { |
1176 | if (cond.phenomenon != PHENOMENON_NONE && |
1177 | cond.qualifier == QUALIFIER_THUNDERSTORM) |
1178 | return "weather-storm"; |
1179 | |
1180 | switch (cond.phenomenon) { |
1181 | case PHENOMENON_INVALID: |
1182 | case PHENOMENON_LAST: |
1183 | case PHENOMENON_NONE: |
1184 | break; |
1185 | |
1186 | case PHENOMENON_DRIZZLE: |
1187 | case PHENOMENON_RAIN: |
1188 | case PHENOMENON_UNKNOWN_PRECIPITATION: |
1189 | case PHENOMENON_HAIL: |
1190 | case PHENOMENON_SMALL_HAIL: |
1191 | return "weather-showers"; |
1192 | |
1193 | case PHENOMENON_SNOW: |
1194 | case PHENOMENON_SNOW_GRAINS: |
1195 | case PHENOMENON_ICE_PELLETS: |
1196 | case PHENOMENON_ICE_CRYSTALS: |
1197 | return "weather-snow"; |
1198 | |
1199 | case PHENOMENON_TORNADO: |
1200 | case PHENOMENON_SQUALL: |
1201 | return "weather-storm"; |
1202 | |
1203 | case PHENOMENON_MIST: |
1204 | case PHENOMENON_FOG: |
1205 | case PHENOMENON_SMOKE: |
1206 | case PHENOMENON_VOLCANIC_ASH: |
1207 | case PHENOMENON_SAND: |
1208 | case PHENOMENON_HAZE: |
1209 | case PHENOMENON_SPRAY: |
1210 | case PHENOMENON_DUST: |
1211 | case PHENOMENON_SANDSTORM: |
1212 | case PHENOMENON_DUSTSTORM: |
1213 | case PHENOMENON_FUNNEL_CLOUD: |
1214 | case PHENOMENON_DUST_WHIRLS: |
1215 | return "weather-fog"; |
1216 | } |
1217 | } |
1218 | |
1219 | if (info->midnightSun || |
1220 | (!info->sunriseValid && !info->sunsetValid)) |
1221 | daytime = TRUE(!(0)); |
1222 | else if (info->polarNight) |
1223 | daytime = FALSE(0); |
1224 | else { |
1225 | current_time = time (NULL((void*)0)); |
1226 | daytime = |
1227 | ( !info->sunriseValid || (current_time >= info->sunrise) ) && |
1228 | ( !info->sunsetValid || (current_time < info->sunset) ); |
1229 | } |
1230 | |
1231 | switch (sky) { |
1232 | case SKY_INVALID: |
1233 | case SKY_LAST: |
1234 | case SKY_CLEAR: |
1235 | if (daytime) |
1236 | return "weather-clear"; |
1237 | else { |
1238 | icon = g_stpcpy(icon_buffer, "weather-clear-night"); |
1239 | break; |
1240 | } |
1241 | |
1242 | case SKY_BROKEN: |
1243 | case SKY_SCATTERED: |
1244 | case SKY_FEW: |
1245 | if (daytime) |
1246 | return "weather-few-clouds"; |
1247 | else { |
1248 | icon = g_stpcpy(icon_buffer, "weather-few-clouds-night"); |
1249 | break; |
1250 | } |
1251 | |
1252 | case SKY_OVERCAST: |
1253 | return "weather-overcast"; |
1254 | |
1255 | default: /* unrecognized */ |
1256 | return NULL((void*)0); |
1257 | } |
1258 | |
1259 | /* |
1260 | * A phase-of-moon icon is to be returned. |
1261 | * Determine which one based on the moon's location |
1262 | */ |
1263 | if (info->moonValid && weather_info_get_value_moonphase(info, &moonPhase, &moonLat)) { |
1264 | phase = (gint)((moonPhase * MOON_PHASES36 / 360.) + 0.5); |
1265 | if (phase == MOON_PHASES36) { |
1266 | phase = 0; |
1267 | } else if (phase > 0 && |
1268 | (RADIANS_TO_DEGREES(weather_info_get_location(info)->latitude)((weather_info_get_location(info)->latitude) * 180. / 3.14159265358979323846 ) |
1269 | < moonLat)) { |
1270 | /* |
1271 | * Locations south of the moon's latitude will see the moon in the |
1272 | * northern sky. The moon waxes and wanes from left to right |
1273 | * so we reference an icon running in the opposite direction. |
1274 | */ |
1275 | phase = MOON_PHASES36 - phase; |
1276 | } |
1277 | |
1278 | /* |
1279 | * If the moon is not full then append the angle to the icon string. |
1280 | * Note that an icon by this name is not required to exist: |
1281 | * the caller can use GTK_ICON_LOOKUP_GENERIC_FALLBACK to fall back to |
1282 | * the full moon image. |
1283 | */ |
1284 | if ((0 == (MOON_PHASES36 & 0x1)) && (MOON_PHASES36/2 != phase)) { |
1285 | g_snprintf(icon, sizeof(icon_buffer) - strlen(icon_buffer), |
1286 | "-%03d", phase * 360 / MOON_PHASES36); |
1287 | } |
1288 | } |
1289 | return icon_buffer; |
1290 | } |
1291 | |
1292 | static gboolean |
1293 | temperature_value (gdouble temp_f, |
1294 | TempUnit to_unit, |
1295 | gdouble *value, |
1296 | TempUnit def_unit) |
1297 | { |
1298 | gboolean ok = TRUE(!(0)); |
1299 | |
1300 | *value = 0.0; |
1301 | if (temp_f < -500.0) |
1302 | return FALSE(0); |
1303 | |
1304 | if (to_unit == TEMP_UNIT_DEFAULT) |
1305 | to_unit = def_unit; |
1306 | |
1307 | switch (to_unit) { |
1308 | case TEMP_UNIT_FAHRENHEIT: |
1309 | *value = temp_f; |
1310 | break; |
1311 | case TEMP_UNIT_CENTIGRADE: |
1312 | *value = TEMP_F_TO_C (temp_f)(((temp_f) - 32.0) * (5.0/9.0)); |
1313 | break; |
1314 | case TEMP_UNIT_KELVIN: |
1315 | *value = TEMP_F_TO_K (temp_f)((temp_f + 459.67) * (5.0/9.0)); |
1316 | break; |
1317 | case TEMP_UNIT_INVALID: |
1318 | case TEMP_UNIT_DEFAULT: |
1319 | default: |
1320 | ok = FALSE(0); |
1321 | break; |
1322 | } |
1323 | |
1324 | return ok; |
1325 | } |
1326 | |
1327 | static gboolean |
1328 | speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit) |
1329 | { |
1330 | gboolean ok = TRUE(!(0)); |
1331 | |
1332 | *value = -1.0; |
1333 | |
1334 | if (knots < 0.0) |
1335 | return FALSE(0); |
1336 | |
1337 | if (to_unit == SPEED_UNIT_DEFAULT) |
1338 | to_unit = def_unit; |
1339 | |
1340 | switch (to_unit) { |
1341 | case SPEED_UNIT_KNOTS: |
1342 | *value = knots; |
1343 | break; |
1344 | case SPEED_UNIT_MPH: |
1345 | *value = WINDSPEED_KNOTS_TO_MPH (knots)((knots) * 1.150779); |
1346 | break; |
1347 | case SPEED_UNIT_KPH: |
1348 | *value = WINDSPEED_KNOTS_TO_KPH (knots)((knots) * 1.851965); |
1349 | break; |
1350 | case SPEED_UNIT_MS: |
1351 | *value = WINDSPEED_KNOTS_TO_MS (knots)((knots) * 0.514444); |
1352 | break; |
1353 | case SPEED_UNIT_BFT: |
1354 | *value = WINDSPEED_KNOTS_TO_BFT (knots)(pow ((knots) * 0.615363, 0.666666)); |
1355 | break; |
1356 | case SPEED_UNIT_INVALID: |
1357 | case SPEED_UNIT_DEFAULT: |
1358 | default: |
1359 | ok = FALSE(0); |
1360 | break; |
1361 | } |
1362 | |
1363 | return ok; |
1364 | } |
1365 | |
1366 | static gboolean |
1367 | pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit) |
1368 | { |
1369 | gboolean ok = TRUE(!(0)); |
1370 | |
1371 | *value = -1.0; |
1372 | |
1373 | if (inHg < 0.0) |
1374 | return FALSE(0); |
1375 | |
1376 | if (to_unit == PRESSURE_UNIT_DEFAULT) |
1377 | to_unit = def_unit; |
1378 | |
1379 | switch (to_unit) { |
1380 | case PRESSURE_UNIT_INCH_HG: |
1381 | *value = inHg; |
1382 | break; |
1383 | case PRESSURE_UNIT_MM_HG: |
1384 | *value = PRESSURE_INCH_TO_MM (inHg)((inHg) * 25.40005); |
1385 | break; |
1386 | case PRESSURE_UNIT_KPA: |
1387 | *value = PRESSURE_INCH_TO_KPA (inHg)((inHg) * 3.386); |
1388 | break; |
1389 | case PRESSURE_UNIT_HPA: |
1390 | *value = PRESSURE_INCH_TO_HPA (inHg)((inHg) * 33.86); |
1391 | break; |
1392 | case PRESSURE_UNIT_MB: |
1393 | *value = PRESSURE_INCH_TO_MB (inHg)(((inHg) * 33.86)); |
1394 | break; |
1395 | case PRESSURE_UNIT_ATM: |
1396 | *value = PRESSURE_INCH_TO_ATM (inHg)((inHg) * 0.033421052); |
1397 | break; |
1398 | case PRESSURE_UNIT_INVALID: |
1399 | case PRESSURE_UNIT_DEFAULT: |
1400 | default: |
1401 | ok = FALSE(0); |
1402 | break; |
1403 | } |
1404 | |
1405 | return ok; |
1406 | } |
1407 | |
1408 | static gboolean |
1409 | distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit) |
1410 | { |
1411 | gboolean ok = TRUE(!(0)); |
1412 | |
1413 | *value = -1.0; |
1414 | |
1415 | if (miles < 0.0) |
1416 | return FALSE(0); |
1417 | |
1418 | if (to_unit == DISTANCE_UNIT_DEFAULT) |
1419 | to_unit = def_unit; |
1420 | |
1421 | switch (to_unit) { |
1422 | case DISTANCE_UNIT_MILES: |
1423 | *value = miles; |
1424 | break; |
1425 | case DISTANCE_UNIT_KM: |
1426 | *value = VISIBILITY_SM_TO_KM (miles)((miles) * 1.609344); |
1427 | break; |
1428 | case DISTANCE_UNIT_METERS: |
1429 | *value = VISIBILITY_SM_TO_M (miles)(((miles) * 1.609344) * 1000); |
1430 | break; |
1431 | case DISTANCE_UNIT_INVALID: |
1432 | case DISTANCE_UNIT_DEFAULT: |
1433 | default: |
1434 | ok = FALSE(0); |
1435 | break; |
1436 | } |
1437 | |
1438 | return ok; |
1439 | } |
1440 | |
1441 | gboolean |
1442 | weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky) |
1443 | { |
1444 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1445 | g_return_val_if_fail (sky != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (sky != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "sky != NULL"); return ((0)); } } while (0); |
1446 | |
1447 | if (!info->valid) |
1448 | return FALSE(0); |
1449 | |
1450 | if (info->sky <= SKY_INVALID || info->sky >= SKY_LAST) |
1451 | return FALSE(0); |
1452 | |
1453 | *sky = info->sky; |
1454 | |
1455 | return TRUE(!(0)); |
1456 | } |
1457 | |
1458 | gboolean |
1459 | weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier) |
1460 | { |
1461 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1462 | g_return_val_if_fail (phenomenon != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (phenomenon != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "phenomenon != NULL" ); return ((0)); } } while (0); |
1463 | g_return_val_if_fail (qualifier != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (qualifier != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "qualifier != NULL" ); return ((0)); } } while (0); |
1464 | |
1465 | if (!info->valid) |
1466 | return FALSE(0); |
1467 | |
1468 | if (!info->cond.significant) |
1469 | return FALSE(0); |
1470 | |
1471 | if (!(info->cond.phenomenon > PHENOMENON_INVALID && |
1472 | info->cond.phenomenon < PHENOMENON_LAST && |
1473 | info->cond.qualifier > QUALIFIER_INVALID && |
1474 | info->cond.qualifier < QUALIFIER_LAST)) |
1475 | return FALSE(0); |
1476 | |
1477 | *phenomenon = info->cond.phenomenon; |
1478 | *qualifier = info->cond.qualifier; |
1479 | |
1480 | return TRUE(!(0)); |
1481 | } |
1482 | |
1483 | gboolean |
1484 | weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value) |
1485 | { |
1486 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1487 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1488 | |
1489 | if (!info->valid) |
1490 | return FALSE(0); |
1491 | |
1492 | return temperature_value (info->temp, unit, value, info->temperature_unit); |
1493 | } |
1494 | |
1495 | gboolean |
1496 | weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value) |
1497 | { |
1498 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1499 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1500 | |
1501 | if (!info->valid || !info->tempMinMaxValid) |
1502 | return FALSE(0); |
1503 | |
1504 | return temperature_value (info->temp_min, unit, value, info->temperature_unit); |
1505 | } |
1506 | |
1507 | gboolean |
1508 | weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value) |
1509 | { |
1510 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1511 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1512 | |
1513 | if (!info->valid || !info->tempMinMaxValid) |
1514 | return FALSE(0); |
1515 | |
1516 | return temperature_value (info->temp_max, unit, value, info->temperature_unit); |
1517 | } |
1518 | |
1519 | gboolean |
1520 | weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value) |
1521 | { |
1522 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1523 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1524 | |
1525 | if (!info->valid) |
1526 | return FALSE(0); |
1527 | |
1528 | return temperature_value (info->dew, unit, value, info->temperature_unit); |
1529 | } |
1530 | |
1531 | gboolean |
1532 | weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value) |
1533 | { |
1534 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1535 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1536 | |
1537 | if (!info->valid) |
1538 | return FALSE(0); |
1539 | |
1540 | return temperature_value (calc_apparent (info), unit, value, info->temperature_unit); |
1541 | } |
1542 | |
1543 | gboolean |
1544 | weather_info_get_value_update (WeatherInfo *info, time_t *value) |
1545 | { |
1546 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1547 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1548 | |
1549 | if (!info->valid) |
1550 | return FALSE(0); |
1551 | |
1552 | *value = info->update; |
1553 | |
1554 | return TRUE(!(0)); |
1555 | } |
1556 | |
1557 | gboolean |
1558 | weather_info_get_value_sunrise (WeatherInfo *info, time_t *value) |
1559 | { |
1560 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1561 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1562 | |
1563 | if (!info->valid || !info->sunriseValid) |
1564 | return FALSE(0); |
1565 | |
1566 | *value = info->sunrise; |
1567 | |
1568 | return TRUE(!(0)); |
1569 | } |
1570 | |
1571 | gboolean |
1572 | weather_info_get_value_sunset (WeatherInfo *info, time_t *value) |
1573 | { |
1574 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1575 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1576 | |
1577 | if (!info->valid || !info->sunsetValid) |
1578 | return FALSE(0); |
1579 | |
1580 | *value = info->sunset; |
1581 | |
1582 | return TRUE(!(0)); |
1583 | } |
1584 | |
1585 | gboolean |
1586 | weather_info_get_value_moonphase (WeatherInfo *info, |
1587 | WeatherMoonPhase *value, |
1588 | WeatherMoonLatitude *lat) |
1589 | { |
1590 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1591 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1592 | |
1593 | if (!info->valid || !info->moonValid) |
1594 | return FALSE(0); |
1595 | |
1596 | *value = info->moonphase; |
1597 | *lat = info->moonlatitude; |
1598 | |
1599 | return TRUE(!(0)); |
1600 | } |
1601 | |
1602 | gboolean |
1603 | weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction) |
1604 | { |
1605 | gboolean res = FALSE(0); |
1606 | |
1607 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1608 | g_return_val_if_fail (speed != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (speed != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "speed != NULL") ; return ((0)); } } while (0); |
1609 | g_return_val_if_fail (direction != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (direction != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "direction != NULL" ); return ((0)); } } while (0); |
1610 | |
1611 | if (!info->valid) |
1612 | return FALSE(0); |
1613 | |
1614 | if (info->windspeed < 0.0 || info->wind <= WIND_INVALID || info->wind >= WIND_LAST) |
1615 | return FALSE(0); |
1616 | |
1617 | res = speed_value (info->windspeed, unit, speed, info->speed_unit); |
1618 | *direction = info->wind; |
1619 | |
1620 | return res; |
1621 | } |
1622 | |
1623 | gboolean |
1624 | weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value) |
1625 | { |
1626 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1627 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1628 | |
1629 | if (!info->valid) |
1630 | return FALSE(0); |
1631 | |
1632 | return pressure_value (info->pressure, unit, value, info->pressure_unit); |
1633 | } |
1634 | |
1635 | gboolean |
1636 | weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value) |
1637 | { |
1638 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1639 | g_return_val_if_fail (value != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (value != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "value != NULL") ; return ((0)); } } while (0); |
1640 | |
1641 | if (!info->valid) |
1642 | return FALSE(0); |
1643 | |
1644 | return distance_value (info->visibility, unit, value, info->distance_unit); |
1645 | } |
1646 | |
1647 | /** |
1648 | * weather_info_get_upcoming_moonphases: |
1649 | * @info: WeatherInfo containing the time_t of interest |
1650 | * @phases: An array of four time_t values that will hold the returned values. |
1651 | * The values are estimates of the time of the next new, quarter, full and |
1652 | * three-quarter moons. |
1653 | * |
1654 | * Returns: gboolean indicating success or failure |
1655 | */ |
1656 | gboolean |
1657 | weather_info_get_upcoming_moonphases (WeatherInfo *info, time_t *phases) |
1658 | { |
1659 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
1660 | g_return_val_if_fail (phases != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (phases != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "phases != NULL" ); return ((0)); } } while (0); |
1661 | |
1662 | return calc_moon_phases(info, phases); |
1663 | } |
1664 | |
1665 | static void |
1666 | _weather_internal_check (void) |
1667 | { |
1668 | g_assert (G_N_ELEMENTS (wind_direction_str) == WIND_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((sizeof (wind_direction_str) / sizeof ((wind_direction_str )[0])) == WIND_LAST) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c", 1668, ((const char*) (__func__) ), "G_N_ELEMENTS (wind_direction_str) == WIND_LAST"); } while (0); |
1669 | g_assert (G_N_ELEMENTS (sky_str) == SKY_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((sizeof (sky_str) / sizeof ((sky_str)[0])) == SKY_LAST) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_ ; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c" , 1669, ((const char*) (__func__)), "G_N_ELEMENTS (sky_str) == SKY_LAST" ); } while (0); |
1670 | g_assert (G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((sizeof (conditions_str) / sizeof ((conditions_str)[0]) ) == PHENOMENON_LAST) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c", 1670, ((const char*) (__func__) ), "G_N_ELEMENTS (conditions_str) == PHENOMENON_LAST"); } while (0); |
1671 | g_assert (G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if ((sizeof (conditions_str[0]) / sizeof ((conditions_str[0 ])[0])) == QUALIFIER_LAST) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1)) ; else g_assertion_message_expr ("MateWeather", "weather.c", 1671, ((const char*) (__func__) ), "G_N_ELEMENTS (conditions_str[0]) == QUALIFIER_LAST"); } while (0); |
1672 | } |
File: | weather-metar.c |
Warning: | line 454, column 5 Value stored to 'i' is never read |
Press '?' + to see keyboard shortcuts
+ + +Keyboard shortcuts:
+1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | /* weather-metar.c - Weather server functions (METAR) |
3 | * |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License as |
6 | * published by the Free Software Foundation; either version 2 of the |
7 | * License, or (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, see |
16 | * <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #ifdef HAVE_CONFIG_H1 |
20 | #include <config.h> |
21 | #endif |
22 | |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | #include <sys/types.h> |
26 | #include <regex.h> |
27 | |
28 | #define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE |
29 | #include "weather.h" |
30 | #include "weather-priv.h" |
31 | |
32 | enum { |
33 | TIME_RE, |
34 | WIND_RE, |
35 | VIS_RE, |
36 | COND_RE, |
37 | CLOUD_RE, |
38 | TEMP_RE, |
39 | PRES_RE, |
40 | |
41 | RE_NUM |
42 | }; |
43 | |
44 | /* Return time of weather report as secs since epoch UTC */ |
45 | static time_t |
46 | make_time (gint utcDate, gint utcHour, gint utcMin) |
47 | { |
48 | const time_t now = time (NULL((void*)0)); |
49 | struct tm tm; |
50 | |
51 | localtime_r (&now, &tm); |
52 | |
53 | /* If last reading took place just before midnight UTC on the |
54 | * first, adjust the date downward to allow for the month |
55 | * change-over. This ASSUMES that the reading won't be more than |
56 | * 24 hrs old! */ |
57 | if ((utcDate > tm.tm_mday) && (tm.tm_mday == 1)) { |
58 | tm.tm_mday = 0; /* mktime knows this is the last day of the previous |
59 | * month. */ |
60 | } else { |
61 | tm.tm_mday = utcDate; |
62 | } |
63 | tm.tm_hour = utcHour; |
64 | tm.tm_min = utcMin; |
65 | tm.tm_sec = 0; |
66 | |
67 | /* mktime() assumes value is local, not UTC. Use tm_gmtoff to compensate */ |
68 | #ifdef HAVE_TM_TM_GMOFF1 |
69 | return tm.tm_gmtoff + mktime (&tm); |
70 | #elif defined HAVE_TIMEZONE |
71 | return timezone + mktime (&tm); |
72 | #endif |
73 | } |
74 | |
75 | static void |
76 | metar_tok_time (gchar *tokp, WeatherInfo *info) |
77 | { |
78 | gint day, hr, min; |
79 | |
80 | sscanf (tokp, "%2u%2u%2u", &day, &hr, &min); |
81 | info->update = make_time (day, hr, min); |
82 | } |
83 | |
84 | static void |
85 | metar_tok_wind (gchar *tokp, WeatherInfo *info) |
86 | { |
87 | gchar sdir[4], sspd[4], sgust[4]; |
88 | gint dir, spd = -1; |
89 | gchar *gustp; |
90 | size_t glen; |
91 | |
92 | strncpy (sdir, tokp, 3); |
93 | sdir[3] = 0; |
94 | dir = (!strcmp (sdir, "VRB")) ? -1 : atoi (sdir); |
95 | |
96 | memset (sspd, 0, sizeof (sspd)); |
97 | glen = strspn (tokp + 3, CONST_DIGITS"0123456789"); |
98 | strncpy (sspd, tokp + 3, glen); |
99 | spd = atoi (sspd); |
100 | tokp += glen + 3; |
101 | |
102 | gustp = strchr (tokp, 'G'); |
103 | if (gustp) { |
104 | memset (sgust, 0, sizeof (sgust)); |
105 | glen = strspn (gustp + 1, CONST_DIGITS"0123456789"); |
106 | strncpy (sgust, gustp + 1, glen); |
107 | tokp = gustp + 1 + glen; |
108 | } |
109 | |
110 | if (!strcmp (tokp, "MPS")) |
111 | info->windspeed = WINDSPEED_MS_TO_KNOTS ((WeatherWindSpeed)spd)(((WeatherWindSpeed)spd) / 0.514444); |
112 | else |
113 | info->windspeed = (WeatherWindSpeed)spd; |
114 | |
115 | if ((349 <= dir) || (dir <= 11)) |
116 | info->wind = WIND_N; |
117 | else if ((12 <= dir) && (dir <= 33)) |
118 | info->wind = WIND_NNE; |
119 | else if ((34 <= dir) && (dir <= 56)) |
120 | info->wind = WIND_NE; |
121 | else if ((57 <= dir) && (dir <= 78)) |
122 | info->wind = WIND_ENE; |
123 | else if ((79 <= dir) && (dir <= 101)) |
124 | info->wind = WIND_E; |
125 | else if ((102 <= dir) && (dir <= 123)) |
126 | info->wind = WIND_ESE; |
127 | else if ((124 <= dir) && (dir <= 146)) |
128 | info->wind = WIND_SE; |
129 | else if ((147 <= dir) && (dir <= 168)) |
130 | info->wind = WIND_SSE; |
131 | else if ((169 <= dir) && (dir <= 191)) |
132 | info->wind = WIND_S; |
133 | else if ((192 <= dir) && (dir <= 213)) |
134 | info->wind = WIND_SSW; |
135 | else if ((214 <= dir) && (dir <= 236)) |
136 | info->wind = WIND_SW; |
137 | else if ((237 <= dir) && (dir <= 258)) |
138 | info->wind = WIND_WSW; |
139 | else if ((259 <= dir) && (dir <= 281)) |
140 | info->wind = WIND_W; |
141 | else if ((282 <= dir) && (dir <= 303)) |
142 | info->wind = WIND_WNW; |
143 | else if ((304 <= dir) && (dir <= 326)) |
144 | info->wind = WIND_NW; |
145 | else if ((327 <= dir) && (dir <= 348)) |
146 | info->wind = WIND_NNW; |
147 | } |
148 | |
149 | static void |
150 | metar_tok_vis (gchar *tokp, WeatherInfo *info) |
151 | { |
152 | gchar *pfrac, *pend, *psp; |
153 | gchar sval[6]; |
154 | gint num, den, val; |
155 | |
156 | memset (sval, 0, sizeof (sval)); |
157 | |
158 | if (!strcmp (tokp,"CAVOK")) { |
159 | // "Ceiling And Visibility OK": visibility >= 10 KM |
160 | info->visibility=10000. / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000); |
161 | info->sky = SKY_CLEAR; |
162 | } else if (0 != (pend = strstr (tokp, "SM"))) { |
163 | // US observation: field ends with "SM" |
164 | pfrac = strchr (tokp, '/'); |
165 | if (pfrac) { |
166 | if (*tokp == 'M') { |
167 | info->visibility = 0.001; |
168 | } else { |
169 | num = (*(pfrac - 1) - '0'); |
170 | strncpy (sval, pfrac + 1, pend - pfrac - 1); |
171 | den = atoi (sval); |
172 | info->visibility = |
173 | ((WeatherVisibility)num / ((WeatherVisibility)den)); |
174 | |
175 | psp = strchr (tokp, ' '); |
176 | if (psp) { |
177 | *psp = '\0'; |
178 | val = atoi (tokp); |
179 | info->visibility += (WeatherVisibility)val; |
180 | } |
181 | } |
182 | } else { |
183 | strncpy (sval, tokp, pend - tokp); |
184 | val = atoi (sval); |
185 | info->visibility = (WeatherVisibility)val; |
186 | } |
187 | } else { |
188 | // International observation: NNNN(DD NNNNDD)? |
189 | // For now: use only the minimum visibility and ignore its direction |
190 | strncpy (sval, tokp, strspn (tokp, CONST_DIGITS"0123456789")); |
191 | val = atoi (sval); |
192 | info->visibility = (WeatherVisibility)val / VISIBILITY_SM_TO_M (1.)(((1.) * 1.609344) * 1000); |
193 | } |
194 | } |
195 | |
196 | static void |
197 | metar_tok_cloud (gchar *tokp, WeatherInfo *info) |
198 | { |
199 | gchar stype[4], salt[4]; |
200 | |
201 | strncpy (stype, tokp, 3); |
202 | stype[3] = 0; |
203 | if (strlen (tokp) == 6) { |
204 | strncpy (salt, tokp + 3, 3); |
205 | salt[3] = 0; |
206 | } |
207 | |
208 | if (!strcmp (stype, "CLR")) { |
209 | info->sky = SKY_CLEAR; |
210 | } else if (!strcmp (stype, "SKC")) { |
211 | info->sky = SKY_CLEAR; |
212 | } else if (!strcmp (stype, "NSC")) { |
213 | info->sky = SKY_CLEAR; |
214 | } else if (!strcmp (stype, "BKN")) { |
215 | info->sky = SKY_BROKEN; |
216 | } else if (!strcmp (stype, "SCT")) { |
217 | info->sky = SKY_SCATTERED; |
218 | } else if (!strcmp (stype, "FEW")) { |
219 | info->sky = SKY_FEW; |
220 | } else if (!strcmp (stype, "OVC")) { |
221 | info->sky = SKY_OVERCAST; |
222 | } |
223 | } |
224 | |
225 | static void |
226 | metar_tok_pres (gchar *tokp, WeatherInfo *info) |
227 | { |
228 | if (*tokp == 'A') { |
229 | gchar sintg[3], sfract[3]; |
230 | gint intg, fract; |
231 | |
232 | strncpy (sintg, tokp + 1, 2); |
233 | sintg[2] = 0; |
234 | intg = atoi (sintg); |
235 | |
236 | strncpy (sfract, tokp + 3, 2); |
237 | sfract[2] = 0; |
238 | fract = atoi (sfract); |
239 | |
240 | info->pressure = (WeatherPressure)intg + (((WeatherPressure)fract)/100.0); |
241 | } else { /* *tokp == 'Q' */ |
242 | gchar spres[5]; |
243 | gint pres; |
244 | |
245 | strncpy (spres, tokp + 1, 4); |
246 | spres[4] = 0; |
247 | pres = atoi (spres); |
248 | |
249 | info->pressure = PRESSURE_MBAR_TO_INCH ((WeatherPressure)pres)(((WeatherPressure)pres) * 0.029533373); |
250 | } |
251 | } |
252 | |
253 | static void |
254 | metar_tok_temp (gchar *tokp, WeatherInfo *info) |
255 | { |
256 | gchar *ptemp, *pdew, *psep; |
257 | |
258 | psep = strchr (tokp, '/'); |
259 | *psep = 0; |
260 | ptemp = tokp; |
261 | pdew = psep + 1; |
262 | |
263 | info->temp = (*ptemp == 'M') ? TEMP_C_TO_F (-atoi (ptemp + 1))(((-atoi (ptemp + 1)) * (9.0/5.0)) + 32.0) |
264 | : TEMP_C_TO_F (atoi (ptemp))(((atoi (ptemp)) * (9.0/5.0)) + 32.0); |
265 | if (*pdew) { |
266 | info->dew = (*pdew == 'M') ? TEMP_C_TO_F (-atoi (pdew + 1))(((-atoi (pdew + 1)) * (9.0/5.0)) + 32.0) |
267 | : TEMP_C_TO_F (atoi (pdew))(((atoi (pdew)) * (9.0/5.0)) + 32.0); |
268 | } else { |
269 | info->dew = -1000.0; |
270 | } |
271 | } |
272 | |
273 | static void |
274 | metar_tok_cond (gchar *tokp, WeatherInfo *info) |
275 | { |
276 | gchar squal[3], sphen[4]; |
277 | gchar *pphen; |
278 | |
279 | if ((strlen (tokp) > 3) && ((*tokp == '+') || (*tokp == '-'))) |
280 | ++tokp; /* FIX */ |
281 | |
282 | if ((*tokp == '+') || (*tokp == '-')) |
283 | pphen = tokp + 1; |
284 | else if (strlen (tokp) < 4) |
285 | pphen = tokp; |
286 | else |
287 | pphen = tokp + 2; |
288 | |
289 | memset (squal, 0, sizeof (squal)); |
290 | strncpy (squal, tokp, pphen - tokp); |
291 | squal[pphen - tokp] = 0; |
292 | |
293 | memset (sphen, 0, sizeof (sphen)); |
294 | strncpy (sphen, pphen, sizeof (sphen)); |
295 | sphen[sizeof (sphen)-1] = '\0'; |
296 | |
297 | /* Defaults */ |
298 | info->cond.qualifier = QUALIFIER_NONE; |
299 | info->cond.phenomenon = PHENOMENON_NONE; |
300 | info->cond.significant = FALSE(0); |
301 | |
302 | if (!strcmp (squal, "")) { |
303 | info->cond.qualifier = QUALIFIER_MODERATE; |
304 | } else if (!strcmp (squal, "-")) { |
305 | info->cond.qualifier = QUALIFIER_LIGHT; |
306 | } else if (!strcmp (squal, "+")) { |
307 | info->cond.qualifier = QUALIFIER_HEAVY; |
308 | } else if (!strcmp (squal, "VC")) { |
309 | info->cond.qualifier = QUALIFIER_VICINITY; |
310 | } else if (!strcmp (squal, "MI")) { |
311 | info->cond.qualifier = QUALIFIER_SHALLOW; |
312 | } else if (!strcmp (squal, "BC")) { |
313 | info->cond.qualifier = QUALIFIER_PATCHES; |
314 | } else if (!strcmp (squal, "PR")) { |
315 | info->cond.qualifier = QUALIFIER_PARTIAL; |
316 | } else if (!strcmp (squal, "TS")) { |
317 | info->cond.qualifier = QUALIFIER_THUNDERSTORM; |
318 | } else if (!strcmp (squal, "BL")) { |
319 | info->cond.qualifier = QUALIFIER_BLOWING; |
320 | } else if (!strcmp (squal, "SH")) { |
321 | info->cond.qualifier = QUALIFIER_SHOWERS; |
322 | } else if (!strcmp (squal, "DR")) { |
323 | info->cond.qualifier = QUALIFIER_DRIFTING; |
324 | } else if (!strcmp (squal, "FZ")) { |
325 | info->cond.qualifier = QUALIFIER_FREEZING; |
326 | } else { |
327 | return; |
328 | } |
329 | |
330 | if (!strcmp (sphen, "DZ")) { |
331 | info->cond.phenomenon = PHENOMENON_DRIZZLE; |
332 | } else if (!strcmp (sphen, "RA")) { |
333 | info->cond.phenomenon = PHENOMENON_RAIN; |
334 | } else if (!strcmp (sphen, "SN")) { |
335 | info->cond.phenomenon = PHENOMENON_SNOW; |
336 | } else if (!strcmp (sphen, "SG")) { |
337 | info->cond.phenomenon = PHENOMENON_SNOW_GRAINS; |
338 | } else if (!strcmp (sphen, "IC")) { |
339 | info->cond.phenomenon = PHENOMENON_ICE_CRYSTALS; |
340 | } else if (!strcmp (sphen, "PE")) { |
341 | info->cond.phenomenon = PHENOMENON_ICE_PELLETS; |
342 | } else if (!strcmp (sphen, "GR")) { |
343 | info->cond.phenomenon = PHENOMENON_HAIL; |
344 | } else if (!strcmp (sphen, "GS")) { |
345 | info->cond.phenomenon = PHENOMENON_SMALL_HAIL; |
346 | } else if (!strcmp (sphen, "UP")) { |
347 | info->cond.phenomenon = PHENOMENON_UNKNOWN_PRECIPITATION; |
348 | } else if (!strcmp (sphen, "BR")) { |
349 | info->cond.phenomenon = PHENOMENON_MIST; |
350 | } else if (!strcmp (sphen, "FG")) { |
351 | info->cond.phenomenon = PHENOMENON_FOG; |
352 | } else if (!strcmp (sphen, "FU")) { |
353 | info->cond.phenomenon = PHENOMENON_SMOKE; |
354 | } else if (!strcmp (sphen, "VA")) { |
355 | info->cond.phenomenon = PHENOMENON_VOLCANIC_ASH; |
356 | } else if (!strcmp (sphen, "SA")) { |
357 | info->cond.phenomenon = PHENOMENON_SAND; |
358 | } else if (!strcmp (sphen, "HZ")) { |
359 | info->cond.phenomenon = PHENOMENON_HAZE; |
360 | } else if (!strcmp (sphen, "PY")) { |
361 | info->cond.phenomenon = PHENOMENON_SPRAY; |
362 | } else if (!strcmp (sphen, "DU")) { |
363 | info->cond.phenomenon = PHENOMENON_DUST; |
364 | } else if (!strcmp (sphen, "SQ")) { |
365 | info->cond.phenomenon = PHENOMENON_SQUALL; |
366 | } else if (!strcmp (sphen, "SS")) { |
367 | info->cond.phenomenon = PHENOMENON_SANDSTORM; |
368 | } else if (!strcmp (sphen, "DS")) { |
369 | info->cond.phenomenon = PHENOMENON_DUSTSTORM; |
370 | } else if (!strcmp (sphen, "PO")) { |
371 | info->cond.phenomenon = PHENOMENON_DUST_WHIRLS; |
372 | } else if (!strcmp (sphen, "+FC")) { |
373 | info->cond.phenomenon = PHENOMENON_TORNADO; |
374 | } else if (!strcmp (sphen, "FC")) { |
375 | info->cond.phenomenon = PHENOMENON_FUNNEL_CLOUD; |
376 | } else { |
377 | return; |
378 | } |
379 | |
380 | if ((info->cond.qualifier != QUALIFIER_NONE) || (info->cond.phenomenon != PHENOMENON_NONE)) |
381 | info->cond.significant = TRUE(!(0)); |
382 | } |
383 | |
384 | #define TIME_RE_STR"([0-9]{6})Z" "([0-9]{6})Z" |
385 | #define WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" "(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" |
386 | #define VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" "CAVOK" "((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" \ |
387 | "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" \ |
388 | "CAVOK" |
389 | #define COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" "(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" |
390 | #define CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" "((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" |
391 | #define TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" "(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" |
392 | #define PRES_RE_STR"(A|Q)([0-9]{4})" "(A|Q)([0-9]{4})" |
393 | |
394 | /* POSIX regular expressions do not allow us to express "match whole words |
395 | * only" in a simple way, so we have to wrap them all into |
396 | * (^| )(...regex...)( |$) |
397 | */ |
398 | #define RE_PREFIX"(^| )(" "(^| )(" |
399 | #define RE_SUFFIX")( |$)" ")( |$)" |
400 | |
401 | static regex_t metar_re[RE_NUM]; |
402 | static void (*metar_f[RE_NUM]) (gchar *tokp, WeatherInfo *info); |
403 | |
404 | static void |
405 | metar_init_re (void) |
406 | { |
407 | static gboolean initialized = FALSE(0); |
408 | if (initialized) |
409 | return; |
410 | initialized = TRUE(!(0)); |
411 | |
412 | regcomp (&metar_re[TIME_RE], RE_PREFIX"(^| )(" TIME_RE_STR"([0-9]{6})Z" RE_SUFFIX")( |$)", REG_EXTENDED1); |
413 | regcomp (&metar_re[WIND_RE], RE_PREFIX"(^| )(" WIND_RE_STR"(([0-9]{3})|VRB)([0-9]?[0-9]{2})(G[0-9]?[0-9]{2})?(KT|MPS)" RE_SUFFIX")( |$)", REG_EXTENDED1); |
414 | regcomp (&metar_re[VIS_RE], RE_PREFIX"(^| )(" VIS_RE_STR"((([0-9]?[0-9])|(M?([12] )?([1357]/1?[0-9])))SM)|" "([0-9]{4}(N|NE|E|SE|S|SW|W|NW( [0-9]{4}(N|NE|E|SE|S|SW|W|NW))?)?)|" "CAVOK" RE_SUFFIX")( |$)", REG_EXTENDED1); |
415 | regcomp (&metar_re[COND_RE], RE_PREFIX"(^| )(" COND_RE_STR"(-|\\+)?(VC|MI|BC|PR|TS|BL|SH|DR|FZ)?(DZ|RA|SN|SG|IC|PE|GR|GS|UP|BR|FG|FU|VA|SA|HZ|PY|DU|SQ|SS|DS|PO|\\+?FC)" RE_SUFFIX")( |$)", REG_EXTENDED1); |
416 | regcomp (&metar_re[CLOUD_RE], RE_PREFIX"(^| )(" CLOUD_RE_STR"((CLR|BKN|SCT|FEW|OVC|SKC|NSC)([0-9]{3}|///)?(CB|TCU|///)?)" RE_SUFFIX")( |$)", REG_EXTENDED1); |
417 | regcomp (&metar_re[TEMP_RE], RE_PREFIX"(^| )(" TEMP_RE_STR"(M?[0-9][0-9])/(M?(//|[0-9][0-9])?)" RE_SUFFIX")( |$)", REG_EXTENDED1); |
418 | regcomp (&metar_re[PRES_RE], RE_PREFIX"(^| )(" PRES_RE_STR"(A|Q)([0-9]{4})" RE_SUFFIX")( |$)", REG_EXTENDED1); |
419 | |
420 | metar_f[TIME_RE] = metar_tok_time; |
421 | metar_f[WIND_RE] = metar_tok_wind; |
422 | metar_f[VIS_RE] = metar_tok_vis; |
423 | metar_f[COND_RE] = metar_tok_cond; |
424 | metar_f[CLOUD_RE] = metar_tok_cloud; |
425 | metar_f[TEMP_RE] = metar_tok_temp; |
426 | metar_f[PRES_RE] = metar_tok_pres; |
427 | } |
428 | |
429 | gboolean |
430 | metar_parse (gchar *metar, WeatherInfo *info) |
431 | { |
432 | gchar *p; |
433 | //gchar *rmk; |
434 | gint i, i2; |
435 | regmatch_t rm, rm2; |
436 | gchar *tokp; |
437 | |
438 | g_return_val_if_fail (info != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return ((0)); } } while (0); |
439 | g_return_val_if_fail (metar != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (metar != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "metar != NULL") ; return ((0)); } } while (0); |
440 | |
441 | metar_init_re (); |
442 | |
443 | /* |
444 | * Force parsing to end at "RMK" field. This prevents a subtle |
445 | * problem when info within the remark happens to match an earlier state |
446 | * and, as a result, throws off all the remaining expression |
447 | */ |
448 | if (0 != (p = strstr (metar, " RMK "))) { |
449 | *p = '\0'; |
450 | //rmk = p + 5; // uncomment this if RMK data becomes useful |
451 | } |
452 | |
453 | p = metar; |
454 | i = TIME_RE; |
Value stored to 'i' is never read | |
455 | while (*p) { |
456 | |
457 | i2 = RE_NUM; |
458 | rm2.rm_so = strlen (p); |
459 | rm2.rm_eo = rm2.rm_so; |
460 | |
461 | for (i = 0; i < RE_NUM && rm2.rm_so > 0; i++) { |
462 | if (0 == regexec (&metar_re[i], p, 1, &rm, 0) |
463 | && rm.rm_so < rm2.rm_so) |
464 | { |
465 | i2 = i; |
466 | /* Skip leading and trailing space characters, if present. |
467 | (the regular expressions include those characters to |
468 | only get matches limited to whole words). */ |
469 | if (p[rm.rm_so] == ' ') rm.rm_so++; |
470 | if (p[rm.rm_eo - 1] == ' ') rm.rm_eo--; |
471 | rm2.rm_so = rm.rm_so; |
472 | rm2.rm_eo = rm.rm_eo; |
473 | } |
474 | } |
475 | |
476 | if (i2 != RE_NUM) { |
477 | tokp = g_strndup (p + rm2.rm_so, rm2.rm_eo - rm2.rm_so); |
478 | metar_f[i2] (tokp, info); |
479 | g_free (tokp); |
480 | } |
481 | |
482 | p += rm2.rm_eo; |
483 | p += strspn (p, " "); |
484 | } |
485 | return TRUE(!(0)); |
486 | } |
487 | |
488 | static void |
489 | metar_finish (SoupSession *session, SoupMessage *msg, gpointer data) |
490 | { |
491 | WeatherInfo *info = (WeatherInfo *)data; |
492 | WeatherLocation *loc; |
493 | const gchar *p, *endtag; |
494 | gchar *searchkey, *metar; |
495 | gboolean success = FALSE(0); |
496 | |
497 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
498 | |
499 | if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)((msg->status_code) >= 200 && (msg->status_code ) < 300)) { |
500 | if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)((msg->status_code) > 0 && (msg->status_code ) < 100)) |
501 | info->network_error = TRUE(!(0)); |
502 | else { |
503 | /* Translators: %d is an error code, and %s the error string */ |
504 | g_warning (_("Failed to get METAR data: %d %s.\n")(mateweather_gettext ("Failed to get METAR data: %d %s.\n")), |
505 | msg->status_code, msg->reason_phrase); |
506 | } |
507 | request_done (info, FALSE(0)); |
508 | return; |
509 | } |
510 | |
511 | loc = info->location; |
512 | |
513 | searchkey = g_strdup_printf ("<raw_text>%s", loc->code); |
514 | p = strstr (msg->response_body->data, searchkey); |
515 | g_free (searchkey); |
516 | if (p) { |
517 | p += WEATHER_LOCATION_CODE_LEN4 + 11; |
518 | endtag = strstr (p, "</raw_text>"); |
519 | if (endtag) |
520 | metar = g_strndup (p, endtag - p); |
521 | else |
522 | metar = g_strdup (p); |
523 | success = metar_parse (metar, info); |
524 | g_free (metar); |
525 | } else if (!strstr (msg->response_body->data, "aviationweather.gov")) { |
526 | /* The response doesn't even seem to have come from NOAA... |
527 | * most likely it is a wifi hotspot login page. Call that a |
528 | * network error. |
529 | */ |
530 | info->network_error = TRUE(!(0)); |
531 | } |
532 | |
533 | info->valid = success; |
534 | request_done (info, TRUE(!(0))); |
535 | } |
536 | |
537 | /* Read current conditions and fill in info structure */ |
538 | void |
539 | metar_start_open (WeatherInfo *info) |
540 | { |
541 | WeatherLocation *loc; |
542 | SoupMessage *msg; |
543 | |
544 | g_return_if_fail (info != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (info != ((void*)0)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 1))) { } else { g_return_if_fail_warning ("MateWeather", ((const char*) (__func__)), "info != NULL"); return; } } while (0); |
545 | info->valid = info->network_error = FALSE(0); |
546 | loc = info->location; |
547 | if (loc == NULL((void*)0)) { |
548 | g_warning (_("WeatherInfo missing location")(mateweather_gettext ("WeatherInfo missing location"))); |
549 | return; |
550 | } |
551 | |
552 | msg = soup_form_request_new ( |
553 | "GET", "https://www.aviationweather.gov/adds/dataserver_current/httpparam", |
554 | "dataSource", "metars", |
555 | "requestType", "retrieve", |
556 | "format", "xml", |
557 | "hoursBeforeNow", "3", |
558 | "mostRecent", "true", |
559 | "fields", "raw_text", |
560 | "stationString", loc->code, |
561 | NULL((void*)0)); |
562 | soup_session_queue_message (info->session, msg, metar_finish, info); |
563 | |
564 | info->requests_pending++; |
565 | } |