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
23 # if TIME_WITH_SYS_TIME
24 # include <sys/time.h>
28 # include <sys/time.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;
55 time_t find_next_time(char *file
, char *pat
, int minutes
){
60 mintime
=time(NULL
)/60+15;
61 if((fp
=fopen(file
, "r"))==NULL
) return mintime
;
66 if(strstr(s
, pat
)!=NULL
) break;
71 if(s
==NULL
) return mintime
;
72 t
=parse_time_string(s
)/60+minutes
;
74 return (t
>mintime
)?t
:mintime
;
77 time_t parse_time_string(char *s
){
79 int ovector
[ovecsize
];
85 date
=pcre_compile("\\b(\\d+)/(\\d+)/(\\d+)\\s+(\\d\\d)(\\d\\d)\\s*UTC\\b", 0, (const char **)&e
, &i
, NULL
);
87 warn("find_next PCRE error: %s at %i", e
, i
);
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;
100 pcre_free_substring(e
);
101 if(pcre_get_substring(s
, ovector
, ovalue
, 2, (const char **)&e
)<0) return 0;
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;
109 pcre_free_substring(e
);
110 if(pcre_get_substring(s
, ovector
, ovalue
, 5, (const char **)&e
)<0) return 0;
112 pcre_free_substring(e
);
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");
123 memset(f
->ID
, '\0', 4);
125 strncpy(f
->ID
, ID
, 3);
129 forecasts
[num_forecasts
-1]=f
;
133 void reset_forecast(struct forecast
*f
){
134 f
->last_update
=time(NULL
);
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 &&
172 static int is_forecast_current(struct forecast
*f
, time_t now
){
176 t
+=(f
->hour
<0)?86399:3599;
180 static int compar(const void *aa
, const void *bb
){
181 struct forecast
*a
=*(struct forecast
**)aa
;
182 struct forecast
*b
=*(struct forecast
**)bb
;
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 */
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
);
216 time_t forecast_time(struct forecast
*f
){
219 if(f
->time
!=-1) return f
->time
;
221 tm
.tm_mon
=f
->month
-1;
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
){
236 if(i
<0 || i
>num_forecasts
){
238 memset(current_ID
, 0, 4);
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){
258 if(!changed
&& current
!=NULL
&& is_forecast_current(current
, now
)) return;
262 target_hour
=current_hour
;
263 memcpy(target_ID
, current_ID
, 4);
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))
273 if(memcmp(forecasts
[i
]->ID
, target_ID
, 4)) tmpdiff
++;
274 if(current
==NULL
|| tmpdiff
<curdiff
){
281 struct forecast
*current_forecast_get(void){
286 static inline int mod(int i
, int n
){
291 void current_forecast_next(int dir
){
295 if(num_forecasts
==0) return;
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
)){
306 if(i
==current_index
){