Fix two bugs related to command execution:
[dockapps.git] / wmweather+ / forecast.c
blob0a12051b97b91255fb4a753bef4565124bcf1038
1 #include "config.h"
3 /* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <stdio.h>
21 #include <stdlib.h>
22 #if TM_IN_SYS_TIME
23 # if TIME_WITH_SYS_TIME
24 # include <sys/time.h>
25 # include <time.h>
26 # else
27 # if HAVE_SYS_TIME_H
28 # include <sys/time.h>
29 # else
30 # include <time.h>
31 # endif
32 # endif
33 #else
34 #include <time.h>
35 #endif
36 #include <string.h>
37 #include <limits.h>
38 #include <math.h>
39 #include <pcre.h>
41 #include "forecast.h"
42 #include "convert.h"
43 #include "getLine.h"
44 #include "die.h"
46 /* Important variables */
47 static struct forecast **forecasts=NULL;
48 static int num_forecasts=0;
49 static pcre *date=NULL;
50 static int ovecsize=1;
51 static int changed=0;
53 /* functions */
55 time_t find_next_time(char *file, char *pat, int minutes){
56 FILE *fp;
57 char *s;
58 time_t t, mintime;
60 mintime=time(NULL)/60+15;
61 if((fp=fopen(file, "r"))==NULL) return mintime;
63 s=NULL;
64 while(!feof(fp)){
65 getLine(&s, fp);
66 if(strstr(s, pat)!=NULL) break;
67 free(s);
68 s=NULL;
70 fclose(fp);
71 if(s==NULL) return mintime;
72 t=parse_time_string(s)/60+minutes;
73 free(s);
74 return (t>mintime)?t:mintime;
77 time_t parse_time_string(char *s){
78 struct tm tm;
79 int ovector[ovecsize];
80 int ovalue;
81 char *e;
82 int i;
84 if(date==NULL){
85 date=pcre_compile("\\b(\\d+)/(\\d+)/(\\d+)\\s+(\\d\\d)(\\d\\d)\\s*UTC\\b", 0, (const char **)&e, &i, NULL);
86 if(date==NULL){
87 warn("find_next PCRE error: %s at %i", e, i);
88 return -1;
90 pcre_fullinfo(date, NULL, PCRE_INFO_CAPTURECOUNT, &ovecsize);
91 ovecsize=(ovecsize+1)*3;
92 return parse_time_string(s);
95 ovalue=pcre_exec(date, NULL, s, strlen(s), 0, 0, ovector, ovecsize);
96 if(ovalue<=0) return -1;
98 if(pcre_get_substring(s, ovector, ovalue, 1, (const char **)&e)<0) return 0;
99 tm.tm_mon=atoi(e)-1;
100 pcre_free_substring(e);
101 if(pcre_get_substring(s, ovector, ovalue, 2, (const char **)&e)<0) return 0;
102 tm.tm_mday=atoi(e);
103 pcre_free_substring(e);
104 if(pcre_get_substring(s, ovector, ovalue, 3, (const char **)&e)<0) return 0;
105 tm.tm_year=atoi(e)-1900;
106 pcre_free_substring(e);
107 if(pcre_get_substring(s, ovector, ovalue, 4, (const char **)&e)<0) return 0;
108 tm.tm_hour=atoi(e);
109 pcre_free_substring(e);
110 if(pcre_get_substring(s, ovector, ovalue, 5, (const char **)&e)<0) return 0;
111 tm.tm_min=atoi(e);
112 pcre_free_substring(e);
113 tm.tm_sec=0;
115 return mkgmtime(&tm);
118 void add_forecast(struct forecast *f, char *ID, char *station){
119 if((forecasts=realloc(forecasts, ++num_forecasts*sizeof(*forecasts)))==NULL)
120 die("realloc in add_forecast");
122 if(ID==NULL){
123 memset(f->ID, '\0', 4);
124 } else {
125 strncpy(f->ID, ID, 3);
126 f->ID[3]='\0';
128 f->station=station;
129 forecasts[num_forecasts-1]=f;
130 changed=1;
133 void reset_forecast(struct forecast *f){
134 f->last_update=time(NULL);
135 f->month=0;
136 f->day=-1;
137 f->year=SHRT_MIN;
138 f->wday=-1;
139 f->hour=-1;
140 f->low=999;
141 f->high=999;
142 f->temp=999;
143 f->dewpt=999;
144 f->rh=-1;
145 f->winddir=-1;
146 f->windspeed=-1;
147 f->heatindex=999;
148 f->windchill=999;
149 f->precipamt=-1;
150 f->snowamt=-1;
151 f->sky=-1;
152 f->vis=7;
153 f->obs=0;
154 f->pcp_total=0;
155 f->frz=0;
156 f->snow=0;
157 f->rain=0;
158 f->tstorm=0;
159 f->svtstorm=0;
160 f->moon=NAN;
161 f->time=-1;
162 changed=1;
165 static int is_forecast_valid(const struct forecast *a){
166 return (a->ID[0]!='\0' &&
167 a->month>0 && a->month<=12 &&
168 a->day>0 && a->day<=31 &&
169 a->year!=SHRT_MIN);
172 static int is_forecast_current(struct forecast *f, time_t now){
173 time_t t;
175 t=forecast_time(f);
176 t+=(f->hour<0)?86399:3599;
177 return t>now;
180 static int compar(const void *aa, const void *bb){
181 struct forecast *a=*(struct forecast **)aa;
182 struct forecast *b=*(struct forecast **)bb;
183 int i, j;
185 /* First, any undefined forecast is greater than any defined forecast */
186 i=is_forecast_valid(a);
187 j=is_forecast_valid(b);
188 if(!i && !j) return 0; /* all undef forecasts are equal */
189 if(!i) return 1;
190 if(!j) return -1;
192 /* Any whole-day forecast is greater than any partial forecast */
193 if(a->hour<0 && b->hour>=0) return 1;
194 if(a->hour>=0 && b->hour<0) return -1;
196 /* Ok, compare dates now */
197 if(a->year>b->year) return 1;
198 if(a->year<b->year) return -1;
199 if(a->month>b->month) return 1;
200 if(a->month<b->month) return -1;
201 if(a->day>b->day) return 1;
202 if(a->day<b->day) return -1;
203 if(a->hour>b->hour) return 1;
204 if(a->hour<b->hour) return -1;
206 /* Last resort, sort in alphabetical order by ID */
207 return strcasecmp(a->ID, b->ID);
210 static void sort_forecasts(void){
211 if(forecasts==NULL) return;
212 qsort(forecasts, num_forecasts, sizeof(struct forecast *), compar);
213 changed=0;
216 time_t forecast_time(struct forecast *f){
217 struct tm tm;
219 if(f->time!=-1) return f->time;
220 tm.tm_year=f->year;
221 tm.tm_mon=f->month-1;
222 tm.tm_mday=f->day;
223 tm.tm_hour=(f->hour<0)?0:f->hour;
224 tm.tm_min=tm.tm_sec=0;
225 return (f->time=mktime(&tm));
228 static char current_ID[4]={ '\0', '\0', '\0', '\0' };
229 static int current_index=-1;
230 static struct forecast *current=NULL;
231 static time_t current_time=0;
232 static int current_hour=0;
234 static void set_current(int i){
235 current_index=i;
236 if(i<0 || i>num_forecasts){
237 current=NULL;
238 memset(current_ID, 0, 4);
239 current_time=0;
240 current_hour=0;
241 } else {
242 current=forecasts[i];
243 memcpy(current_ID, current->ID, 4);
244 current_time=forecast_time(current);
245 current_hour=current->hour;
249 static void locate_current(void){
250 int i;
251 time_t now, target;
252 int target_hour;
253 long curdiff=0;
254 long tmpdiff;
255 char target_ID[4];
257 now=time(NULL);
258 if(!changed && current!=NULL && is_forecast_current(current, now)) return;
260 sort_forecasts();
261 target=current_time;
262 target_hour=current_hour;
263 memcpy(target_ID, current_ID, 4);
264 set_current(-1);
266 for(i=0; i<num_forecasts; i++){
267 if(!is_forecast_valid(forecasts[i])) continue;
268 if(!is_forecast_current(forecasts[i], now)) continue;
269 tmpdiff=abs(forecast_time(forecasts[i])-target);
270 if((target_hour<0 && forecasts[i]->hour>=0) ||
271 (target_hour>=0 && forecasts[i]->hour<0))
272 tmpdiff+=31556926;
273 if(memcmp(forecasts[i]->ID, target_ID, 4)) tmpdiff++;
274 if(current==NULL || tmpdiff<curdiff){
275 set_current(i);
276 curdiff=tmpdiff;
281 struct forecast *current_forecast_get(void){
282 locate_current();
283 return current;
286 static inline int mod(int i, int n){
287 i=i%n; if(i<0) i+=n;
288 return i;
291 void current_forecast_next(int dir){
292 int i;
293 time_t now;
295 if(num_forecasts==0) return;
297 locate_current();
298 now=time(NULL);
300 if(current_index<0 || current_index>num_forecasts) current_index=0;
301 for(i=mod(current_index+dir, num_forecasts); ; i=mod(i+dir, num_forecasts)){
302 if(is_forecast_valid(forecasts[i]) && is_forecast_current(forecasts[i], now)){
303 set_current(i);
304 return;
306 if(i==current_index){
307 set_current(-1);
308 return;