summaryrefslogtreecommitdiffabout
path: root/libical/src/libical/icalrecur.c
Unidiff
Diffstat (limited to 'libical/src/libical/icalrecur.c') (more/less context) (show whitespace changes)
-rw-r--r--libical/src/libical/icalrecur.c759
1 files changed, 418 insertions, 341 deletions
diff --git a/libical/src/libical/icalrecur.c b/libical/src/libical/icalrecur.c
index 203ce70..d5a59c6 100644
--- a/libical/src/libical/icalrecur.c
+++ b/libical/src/libical/icalrecur.c
@@ -1,46 +1,50 @@
1/* -*- Mode: C -*- 1/* -*- Mode: C -*-
2 ====================================================================== 2 ======================================================================
3 FILE: icalrecur.c 3 FILE: icalrecur.c
4 CREATOR: eric 16 May 2000 4 CREATOR: eric 16 May 2000
5 5
6 $Id$ 6 $Id$
7 $Locker$ 7 $Locker$
8 8
9 9
10 (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org 10 (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
11 11
12 This program is free software; you can redistribute it and/or modify 12 This program is free software; you can redistribute it and/or modify
13 it under the terms of either: 13 it under the terms of either:
14 14
15 The LGPL as published by the Free Software Foundation, version 15 The LGPL as published by the Free Software Foundation, version
16 2.1, available at: http://www.fsf.org/copyleft/lesser.html 16 2.1, available at: http://www.fsf.org/copyleft/lesser.html
17 17
18 Or: 18 Or:
19 19
20 The Mozilla Public License Version 1.0. You may obtain a copy of 20 The Mozilla Public License Version 1.0. You may obtain a copy of
21 the License at http://www.mozilla.org/MPL/ 21 the License at http://www.mozilla.org/MPL/
22*/
22 23
24/**
25 @file icalrecur.c
26 @brief Implementation of routines for dealing with recurring time
23 27
24 How this code works: 28 How this code works:
25 29
26 Processing starts when the caller generates a new recurrence 30 Processing starts when the caller generates a new recurrence
27 iterator via icalrecur_iterator_new(). This routine copies the 31 iterator via icalrecur_iterator_new(). This routine copies the
28 recurrence rule into the iterator and extracts things like start and 32 recurrence rule into the iterator and extracts things like start and
29 end dates. Then, it checks if the rule is legal, using some logic 33 end dates. Then, it checks if the rule is legal, using some logic
30 from RFC2445 and some logic that probably should be in RFC2445. 34 from RFC2445 and some logic that probably should be in RFC2445.
31 35
32 Then, icalrecur_iterator_new() re-writes some of the BY* 36 Then, icalrecur_iterator_new() re-writes some of the BY*
33 arrays. This involves ( via a call to setup_defaults() ) : 37 arrays. This involves ( via a call to setup_defaults() ) :
34 38
35 1) For BY rule parts with no data ( ie BYSECOND was not specified ) 39 1) For BY rule parts with no data ( ie BYSECOND was not specified )
36 copy the corresponding time part from DTSTART into the BY array. ( 40 copy the corresponding time part from DTSTART into the BY array. (
37 So impl->by_ptrs[BY_SECOND] will then have one element if is 41 So impl->by_ptrs[BY_SECOND] will then have one element if is
38 originally had none ) This only happens if the BY* rule part data 42 originally had none ) This only happens if the BY* rule part data
39 would expand the number of occurrences in the occurrence set. This 43 would expand the number of occurrences in the occurrence set. This
40 lets the code ignore DTSTART later on and still use it to get the 44 lets the code ignore DTSTART later on and still use it to get the
41 time parts that were not specified in any other way. 45 time parts that were not specified in any other way.
42 46
43 2) For the by rule part that are not the same interval as the 47 2) For the by rule part that are not the same interval as the
44 frequency -- for HOURLY anything but BYHOUR, for instance -- copy the 48 frequency -- for HOURLY anything but BYHOUR, for instance -- copy the
45 first data element from the rule part into the first occurrence. For 49 first data element from the rule part into the first occurrence. For
46 example, for "INTERVAL=MONTHLY and BYHOUR=10,30", initialize the 50 example, for "INTERVAL=MONTHLY and BYHOUR=10,30", initialize the
@@ -109,89 +113,91 @@
109 113
110 Finally, icalrecur_iterator_next() does a few other checks on the 114 Finally, icalrecur_iterator_next() does a few other checks on the
111 time value, and if it passes, it returns the time. 115 time value, and if it passes, it returns the time.
112 116
113 A note about the end_of_data flag. The flag indicates that the 117 A note about the end_of_data flag. The flag indicates that the
114 routine is at the end of its data -- the last BY rule if the routine 118 routine is at the end of its data -- the last BY rule if the routine
115 is using by rules, or the last day of the week/month/year/etc if 119 is using by rules, or the last day of the week/month/year/etc if
116 not. 120 not.
117 121
118 This flag is usually set early in a next_* routine and returned in 122 This flag is usually set early in a next_* routine and returned in
119 the end. The way it is used allows the next_* routine to set the 123 the end. The way it is used allows the next_* routine to set the
120 last time back to the first element in a BYxx rule, and then signal 124 last time back to the first element in a BYxx rule, and then signal
121 to the higer level routine to increment the next higher level. For 125 to the higer level routine to increment the next higher level. For
122 instance. WITH FREQ=MONTHLY;BYDAY=TU,FR, After next_weekday_by_month 126 instance. WITH FREQ=MONTHLY;BYDAY=TU,FR, After next_weekday_by_month
123 runs though both TU and FR, it sets the week day back to TU and sets 127 runs though both TU and FR, it sets the week day back to TU and sets
124 end_of_data to 1x. This signals next_month to increment the month. 128 end_of_data to 1x. This signals next_month to increment the month.
125 129
126 130
127 ======================================================================*/ 131 ======================================================================*/
128 132
129#ifdef HAVE_CONFIG_H 133#ifdef HAVE_CONFIG_H
130#include "config.h" 134#include "config.h"
131#endif 135#endif
132 136
137#ifdef HAVE_STDINT_H
138#include <stdint.h>
139#endif
140
133#include "icalrecur.h" 141#include "icalrecur.h"
134 142
135#ifdef ICAL_NO_LIBICAL
136#define icalerror_set_errno(x)
137#define icalerror_check_arg_rv(x,y)
138#else
139#include "icalerror.h" 143#include "icalerror.h"
140#include "icalmemory.h" 144#include "icalmemory.h"
141#endif
142 145
143#include <stdlib.h> /* for malloc */ 146#include <stdlib.h> /* for malloc */
144#include <errno.h> /* for errno */ 147#include <errno.h> /* for errno */
145#include <string.h> /* for strdup and strchr*/ 148#include <string.h> /* for strdup and strchr*/
146#include <assert.h> 149#include <assert.h>
147#include <stddef.h> /* For offsetof() macro */ 150#include <stddef.h> /* For offsetof() macro */
148 151
149#include "pvl.h" 152#include "pvl.h"
150 153
154/** This is the last year we will go up to, since 32-bit time_t values
155 only go up to the start of 2038. */
156 #define MAX_TIME_T_YEAR2037
157
151#define TEMP_MAX 1024 158#define TEMP_MAX 1024
152 159
153 160
154#define BYDAYIDX impl->by_indices[BY_DAY] 161#define BYDAYIDX impl->by_indices[BY_DAY]
155#define BYDAYPTR impl->by_ptrs[BY_DAY] 162#define BYDAYPTR impl->by_ptrs[BY_DAY]
156 163
157#define BYMONIDX impl->by_indices[BY_MONTH] 164#define BYMONIDX impl->by_indices[BY_MONTH]
158#define BYMONPTR impl->by_ptrs[BY_MONTH] 165#define BYMONPTR impl->by_ptrs[BY_MONTH]
159 166
160#define BYMDIDX impl->by_indices[BY_MONTH_DAY] 167#define BYMDIDX impl->by_indices[BY_MONTH_DAY]
161#define BYMDPTR impl->by_ptrs[BY_MONTH_DAY] 168#define BYMDPTR impl->by_ptrs[BY_MONTH_DAY]
162 169
163#define BYWEEKIDX impl->by_indices[BY_WEEK_NO] 170#define BYWEEKIDX impl->by_indices[BY_WEEK_NO]
164#define BYWEEKPTR impl->by_ptrs[BY_WEEK_NO] 171#define BYWEEKPTR impl->by_ptrs[BY_WEEK_NO]
165 172
166const char* icalrecur_freq_to_string(icalrecurrencetype_frequency kind); 173const char* icalrecur_freq_to_string(icalrecurrencetype_frequency kind);
167icalrecurrencetype_frequency icalrecur_string_to_freq(const char* str); 174icalrecurrencetype_frequency icalrecur_string_to_freq(const char* str);
168 175
169const char* icalrecur_weekday_to_string(icalrecurrencetype_weekday kind); 176const char* icalrecur_weekday_to_string(icalrecurrencetype_weekday kind);
170icalrecurrencetype_weekday icalrecur_string_to_weekday(const char* str); 177icalrecurrencetype_weekday icalrecur_string_to_weekday(const char* str);
171 178
172 179
173
174/*********************** Rule parsing routines ************************/ 180/*********************** Rule parsing routines ************************/
175 181
176struct icalrecur_parser { 182struct icalrecur_parser {
177 const char* rule; 183 const char* rule;
178 char* copy; 184 char* copy;
179 char* this_clause; 185 char* this_clause;
180 char* next_clause; 186 char* next_clause;
181 187
182 struct icalrecurrencetype rt; 188 struct icalrecurrencetype rt;
183}; 189};
184 190
185const char* icalrecur_first_clause(struct icalrecur_parser *parser) 191const char* icalrecur_first_clause(struct icalrecur_parser *parser)
186{ 192{
187 char *idx; 193 char *idx;
188 parser->this_clause = parser->copy; 194 parser->this_clause = parser->copy;
189 195
190 idx = strchr(parser->this_clause,';'); 196 idx = strchr(parser->this_clause,';');
191 197
192 if (idx == 0){ 198 if (idx == 0){
193 parser->next_clause = 0; 199 parser->next_clause = 0;
194 return 0; 200 return 0;
195 } 201 }
196 202
197 *idx = 0; 203 *idx = 0;
@@ -232,580 +238,585 @@ void icalrecur_clause_name_and_value(struct icalrecur_parser *parser,
232{ 238{
233 char *idx; 239 char *idx;
234 240
235 *name = parser->this_clause; 241 *name = parser->this_clause;
236 242
237 idx = strchr(parser->this_clause,'='); 243 idx = strchr(parser->this_clause,'=');
238 244
239 if (idx == 0){ 245 if (idx == 0){
240 *name = 0; 246 *name = 0;
241 *value = 0; 247 *value = 0;
242 return; 248 return;
243 } 249 }
244 250
245 *idx = 0; 251 *idx = 0;
246 idx++; 252 idx++;
247 *value = idx; 253 *value = idx;
248} 254}
249 255
250void icalrecur_add_byrules(struct icalrecur_parser *parser, short *array, 256void icalrecur_add_byrules(struct icalrecur_parser *parser, short *array,
251 int size, char* vals) 257 int size, char* vals)
252{ 258{
253 char *t, *n; 259 char *t, *n;
254 int i=0; 260 int i=0;
255 int sign = 1; 261 int sign = 1;
256 short v; 262 int v;
257 263
258 n = vals; 264 n = vals;
259 265
260 while(n != 0){ 266 while(n != 0){
261 267
262 if(i == size){ 268 if(i == size){
263 return; 269 return;
264 } 270 }
265 271
266 t = n; 272 t = n;
267 273
268 n = strchr(t,','); 274 n = strchr(t,',');
269 275
270 if(n != 0){ 276 if(n != 0){
271 *n = 0; 277 *n = 0;
272 n++; 278 n++;
273 } 279 }
274 280
275 /* Get optional sign. HACK. sign is not allowed for all BYxxx 281 /* Get optional sign. HACK. sign is not allowed for all BYxxx
276 rule parts */ 282 rule parts */
277 if( *t == '-'){ 283 if( *t == '-'){
278 sign = -1; 284 sign = -1;
279 t++; 285 t++;
280 } else if (*t == '+'){ 286 } else if (*t == '+'){
281 sign = 1; 287 sign = 1;
282 t++; 288 t++;
289 } else {
290 sign = 1;
283 } 291 }
284 292
285 v = atoi(t) * sign ; 293 v = atoi(t) * sign ;
286 294
287 295
288 array[i++] = v; 296 array[i++] = (short)v;
289 array[i] = ICAL_RECURRENCE_ARRAY_MAX; 297 array[i] = ICAL_RECURRENCE_ARRAY_MAX;
290 298
291 } 299 }
292 300
293} 301}
294 302
295void icalrecur_add_bydayrules(struct icalrecur_parser *parser, const char* vals) 303void icalrecur_add_bydayrules(struct icalrecur_parser *parser, const char* vals)
296{ 304{
297 305
298 char *t, *n; 306 char *t, *n;
299 int i=0; 307 int i=0;
300 int sign = 1; 308 int sign = 1;
301 int weekno = 0; 309 int weekno = 0;
302 icalrecurrencetype_weekday wd; 310 icalrecurrencetype_weekday wd;
303 short *array = parser->rt.by_day; 311 short *array = parser->rt.by_day;
304 char* end; 312 char* end;
305 char* vals_copy; 313 char* vals_copy;
306 314
307 vals_copy = icalmemory_strdup(vals); 315 vals_copy = icalmemory_strdup(vals);
308 316
309 end = (char*)vals_copy+strlen(vals_copy); 317 end = (char*)vals_copy+strlen(vals_copy);
310 n = vals_copy; 318 n = vals_copy;
311 319
312 while(n != 0){ 320 while(n != 0){
313 321
314 322
315 t = n; 323 t = n;
316 324
317 n = strchr(t,','); 325 n = strchr(t,',');
318 326
319 if(n != 0){ 327 if(n != 0){
320 *n = 0; 328 *n = 0;
321 n++; 329 n++;
322 } 330 }
323 331
324 /* Get optional sign. */ 332 /* Get optional sign. */
325 if( *t == '-'){ 333 if( *t == '-'){
326 sign = -1; 334 sign = -1;
327 t++; 335 t++;
328 } else if (*t == '+'){ 336 } else if (*t == '+'){
329 sign = 1; 337 sign = 1;
330 t++; 338 t++;
331 } else { 339 } else {
332 sign = 1; 340 sign = 1;
333 } 341 }
334 342
335 weekno = 0;
336 /* Get Optional weekno */ 343 /* Get Optional weekno */
337 if( sscanf(t,"%d",&weekno) != 0){ 344 weekno = strtol(t,&t,10);
338 if (n != 0){ 345
339 int weeknolen = (n-t)-3; /* 3 -> one for \0, 2 for day name */ 346 /* Outlook/Exchange generate "BYDAY=MO, FR" and "BYDAY=2 TH".
340 /* could use abs(log10(weekno))+1, but that needs libm */ 347 * Cope with that.
341 t += weeknolen; 348 */
342 } else { 349 if (*t == ' ')
343 t = end -2; 350 t++;
344 }
345 }
346 351
347 wd = icalrecur_string_to_weekday(t); 352 wd = icalrecur_string_to_weekday(t);
348 353
349 array[i++] = sign* ((int)wd + 8*weekno); 354 array[i++] = (short)(sign* (wd + 8*weekno));
350 array[i] = ICAL_RECURRENCE_ARRAY_MAX; 355 array[i] = ICAL_RECURRENCE_ARRAY_MAX;
351 356
352 } 357 }
353 358
354 free(vals_copy); 359 free(vals_copy);
355 360
356} 361}
357 362
358 363
359struct icalrecurrencetype icalrecurrencetype_from_string(const char* str) 364struct icalrecurrencetype icalrecurrencetype_from_string(const char* str)
360{ 365{
361 struct icalrecur_parser parser; 366 struct icalrecur_parser parser;
362 367
363 memset(&parser,0,sizeof(parser)); 368 memset(&parser,0,sizeof(parser));
364 icalrecurrencetype_clear(&parser.rt); 369 icalrecurrencetype_clear(&parser.rt);
365 370
366 icalerror_check_arg_re(str!=0,"str",parser.rt); 371 icalerror_check_arg_re(str!=0,"str",parser.rt);
367 372
368 373
369 /* Set up the parser struct */ 374 /* Set up the parser struct */
370 parser.rule = str; 375 parser.rule = str;
371 parser.copy = icalmemory_strdup(parser.rule); 376 parser.copy = icalmemory_strdup(parser.rule);
372 parser.this_clause = parser.copy; 377 parser.this_clause = parser.copy;
373 378
374 if(parser.copy == 0){ 379 if(parser.copy == 0){
375 icalerror_set_errno(ICAL_NEWFAILED_ERROR); 380 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
376 return parser.rt; 381 return parser.rt;
377 } 382 }
378 383
379 /* Loop through all of the clauses */ 384 /* Loop through all of the clauses */
380 for(icalrecur_first_clause(&parser); 385 for(icalrecur_first_clause(&parser);
381 parser.this_clause != 0; 386 parser.this_clause != 0;
382 icalrecur_next_clause(&parser)) 387 icalrecur_next_clause(&parser))
383 { 388 {
384 char *name, *value; 389 char *name, *value;
385 icalrecur_clause_name_and_value(&parser,&name,&value); 390 icalrecur_clause_name_and_value(&parser,&name,&value);
386 391
387 if(name == 0){ 392 if(name == 0){
388 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 393 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
389 icalrecurrencetype_clear(&parser.rt); 394 icalrecurrencetype_clear(&parser.rt);
395 free(parser.copy);
390 return parser.rt; 396 return parser.rt;
391 } 397 }
392 398
393 if (strcmp(name,"FREQ") == 0){ 399 if (strcmp(name,"FREQ") == 0){
394 parser.rt.freq = icalrecur_string_to_freq(value); 400 parser.rt.freq = icalrecur_string_to_freq(value);
395 } else if (strcmp(name,"COUNT") == 0){ 401 } else if (strcmp(name,"COUNT") == 0){
396 parser.rt.count = atoi(value); 402 parser.rt.count = atoi(value);
397 } else if (strcmp(name,"UNTIL") == 0){ 403 } else if (strcmp(name,"UNTIL") == 0){
398 parser.rt.until = icaltime_from_string(value); 404 parser.rt.until = icaltime_from_string(value);
399 } else if (strcmp(name,"INTERVAL") == 0){ 405 } else if (strcmp(name,"INTERVAL") == 0){
400 parser.rt.interval = atoi(value); 406 parser.rt.interval = (short)atoi(value);
401 } else if (strcmp(name,"WKST") == 0){ 407 } else if (strcmp(name,"WKST") == 0){
402 parser.rt.week_start = icalrecur_string_to_weekday(value); 408 parser.rt.week_start = icalrecur_string_to_weekday(value);
403 } else if (strcmp(name,"BYSECOND") == 0){ 409 } else if (strcmp(name,"BYSECOND") == 0){
404 icalrecur_add_byrules(&parser,parser.rt.by_second, 410 icalrecur_add_byrules(&parser,parser.rt.by_second,
405 ICAL_BY_SECOND_SIZE,value); 411 ICAL_BY_SECOND_SIZE,value);
406 } else if (strcmp(name,"BYMINUTE") == 0){ 412 } else if (strcmp(name,"BYMINUTE") == 0){
407 icalrecur_add_byrules(&parser,parser.rt.by_minute, 413 icalrecur_add_byrules(&parser,parser.rt.by_minute,
408 ICAL_BY_MINUTE_SIZE,value); 414 ICAL_BY_MINUTE_SIZE,value);
409 } else if (strcmp(name,"BYHOUR") == 0){ 415 } else if (strcmp(name,"BYHOUR") == 0){
410 icalrecur_add_byrules(&parser,parser.rt.by_hour, 416 icalrecur_add_byrules(&parser,parser.rt.by_hour,
411 ICAL_BY_HOUR_SIZE,value); 417 ICAL_BY_HOUR_SIZE,value);
412 } else if (strcmp(name,"BYDAY") == 0){ 418 } else if (strcmp(name,"BYDAY") == 0){
413 icalrecur_add_bydayrules(&parser,value); 419 icalrecur_add_bydayrules(&parser,value);
414 } else if (strcmp(name,"BYMONTHDAY") == 0){ 420 } else if (strcmp(name,"BYMONTHDAY") == 0){
415 icalrecur_add_byrules(&parser,parser.rt.by_month_day, 421 icalrecur_add_byrules(&parser,parser.rt.by_month_day,
416 ICAL_BY_MONTHDAY_SIZE,value); 422 ICAL_BY_MONTHDAY_SIZE,value);
417 } else if (strcmp(name,"BYYEARDAY") == 0){ 423 } else if (strcmp(name,"BYYEARDAY") == 0){
418 icalrecur_add_byrules(&parser,parser.rt.by_year_day, 424 icalrecur_add_byrules(&parser,parser.rt.by_year_day,
419 ICAL_BY_YEARDAY_SIZE,value); 425 ICAL_BY_YEARDAY_SIZE,value);
420 } else if (strcmp(name,"BYWEEKNO") == 0){ 426 } else if (strcmp(name,"BYWEEKNO") == 0){
421 icalrecur_add_byrules(&parser,parser.rt.by_week_no, 427 icalrecur_add_byrules(&parser,parser.rt.by_week_no,
422 ICAL_BY_WEEKNO_SIZE,value); 428 ICAL_BY_WEEKNO_SIZE,value);
423 } else if (strcmp(name,"BYMONTH") == 0){ 429 } else if (strcmp(name,"BYMONTH") == 0){
424 icalrecur_add_byrules(&parser,parser.rt.by_month, 430 icalrecur_add_byrules(&parser,parser.rt.by_month,
425 ICAL_BY_MONTH_SIZE,value); 431 ICAL_BY_MONTH_SIZE,value);
426 } else if (strcmp(name,"BYSETPOS") == 0){ 432 } else if (strcmp(name,"BYSETPOS") == 0){
427 icalrecur_add_byrules(&parser,parser.rt.by_set_pos, 433 icalrecur_add_byrules(&parser,parser.rt.by_set_pos,
428 ICAL_BY_SETPOS_SIZE,value); 434 ICAL_BY_SETPOS_SIZE,value);
429 } else { 435 } else {
430 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 436 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
431 icalrecurrencetype_clear(&parser.rt); 437 icalrecurrencetype_clear(&parser.rt);
438 free(parser.copy);
432 return parser.rt; 439 return parser.rt;
433 } 440 }
434 441
435 } 442 }
436 443
437 free(parser.copy); 444 free(parser.copy);
438 445
439 return parser.rt; 446 return parser.rt;
440 447
441} 448}
442 449
443#ifndef ICAL_NO_LIBICAL 450static struct { char* str;size_t offset; int limit; } recurmap[] =
444
445struct { char* str;size_t offset; short limit; } recurmap[] =
446{ 451{
447 {";BYSECOND=",offsetof(struct icalrecurrencetype,by_second),60}, 452 {";BYSECOND=",offsetof(struct icalrecurrencetype,by_second),60},
448 {";BYMINUTE=",offsetof(struct icalrecurrencetype,by_minute),60}, 453 {";BYMINUTE=",offsetof(struct icalrecurrencetype,by_minute),60},
449 {";BYHOUR=",offsetof(struct icalrecurrencetype,by_hour),24}, 454 {";BYHOUR=",offsetof(struct icalrecurrencetype,by_hour),24},
450 {";BYDAY=",offsetof(struct icalrecurrencetype,by_day),7}, 455 {";BYDAY=",offsetof(struct icalrecurrencetype,by_day),7},
451 {";BYMONTHDAY=",offsetof(struct icalrecurrencetype,by_month_day),31}, 456 {";BYMONTHDAY=",offsetof(struct icalrecurrencetype,by_month_day),31},
452 {";BYYEARDAY=",offsetof(struct icalrecurrencetype,by_year_day),366}, 457 {";BYYEARDAY=",offsetof(struct icalrecurrencetype,by_year_day),366},
453 {";BYWEEKNO=",offsetof(struct icalrecurrencetype,by_week_no),52}, 458 {";BYWEEKNO=",offsetof(struct icalrecurrencetype,by_week_no),52},
454 {";BYMONTH=",offsetof(struct icalrecurrencetype,by_month),12}, 459 {";BYMONTH=",offsetof(struct icalrecurrencetype,by_month),12},
455 {";BYSETPOS=",offsetof(struct icalrecurrencetype,by_set_pos),366}, 460 {";BYSETPOS=",offsetof(struct icalrecurrencetype,by_set_pos),366},
456 {0,0,0}, 461 {0,0,0},
457}; 462};
458 463
459/* A private routine in icalvalue.c */ 464/* A private routine in icalvalue.c */
465void print_date_to_string(char* str, struct icaltimetype *data);
460void print_datetime_to_string(char* str, struct icaltimetype *data); 466void print_datetime_to_string(char* str, struct icaltimetype *data);
461 467
462char* icalrecurrencetype_as_string(struct icalrecurrencetype *recur) 468char* icalrecurrencetype_as_string(struct icalrecurrencetype *recur)
463{ 469{
464 char* str; 470 char* str;
465 char *str_p; 471 char *str_p;
466 size_t buf_sz = 200; 472 size_t buf_sz = 200;
467 char temp[20]; 473 char temp[20];
468 int i,j; 474 int i,j;
469 475
470 if(recur->freq == ICAL_NO_RECURRENCE){ 476 if(recur->freq == ICAL_NO_RECURRENCE){
471 return 0; 477 return 0;
472 } 478 }
473 479
474 str = (char*)icalmemory_tmp_buffer(buf_sz); 480 str = (char*)icalmemory_tmp_buffer(buf_sz);
475 str_p = str; 481 str_p = str;
476 482
477 icalmemory_append_string(&str,&str_p,&buf_sz,"FREQ="); 483 icalmemory_append_string(&str,&str_p,&buf_sz,"FREQ=");
478 icalmemory_append_string(&str,&str_p,&buf_sz, 484 icalmemory_append_string(&str,&str_p,&buf_sz,
479 icalrecur_freq_to_string(recur->freq)); 485 icalrecur_freq_to_string(recur->freq));
480 486
481 if(recur->until.year != 0){ 487 if(recur->until.year != 0){
482 488
483 temp[0] = 0; 489 temp[0] = 0;
490 if (recur->until.is_date)
491 print_date_to_string(temp,&(recur->until));
492 else
484 print_datetime_to_string(temp,&(recur->until)); 493 print_datetime_to_string(temp,&(recur->until));
485 494
486 icalmemory_append_string(&str,&str_p,&buf_sz,";UNTIL="); 495 icalmemory_append_string(&str,&str_p,&buf_sz,";UNTIL=");
487 icalmemory_append_string(&str,&str_p,&buf_sz, temp); 496 icalmemory_append_string(&str,&str_p,&buf_sz, temp);
488 } 497 }
489 498
490 if(recur->count != 0){ 499 if(recur->count != 0){
491 sprintf(temp,"%d",recur->count); 500 sprintf(temp,"%d",recur->count);
492 icalmemory_append_string(&str,&str_p,&buf_sz,";COUNT="); 501 icalmemory_append_string(&str,&str_p,&buf_sz,";COUNT=");
493 icalmemory_append_string(&str,&str_p,&buf_sz, temp); 502 icalmemory_append_string(&str,&str_p,&buf_sz, temp);
494 } 503 }
495 504
496 if(recur->interval != 0){ 505 if(recur->interval != 0){
497 sprintf(temp,"%d",recur->interval); 506 sprintf(temp,"%d",recur->interval);
498 icalmemory_append_string(&str,&str_p,&buf_sz,";INTERVAL="); 507 icalmemory_append_string(&str,&str_p,&buf_sz,";INTERVAL=");
499 icalmemory_append_string(&str,&str_p,&buf_sz, temp); 508 icalmemory_append_string(&str,&str_p,&buf_sz, temp);
500 } 509 }
501 510
502 for(j =0; recurmap[j].str != 0; j++){ 511 for(j =0; recurmap[j].str != 0; j++){
503 short* array = (short*)(recurmap[j].offset+ (size_t)recur); 512 short* array = (short*)(recurmap[j].offset+ (size_t)recur);
504 short limit = recurmap[j].limit; 513 int limit = recurmap[j].limit;
505 514
506 /* Skip unused arrays */ 515 /* Skip unused arrays */
507 if( array[0] != ICAL_RECURRENCE_ARRAY_MAX ) { 516 if( array[0] != ICAL_RECURRENCE_ARRAY_MAX ) {
508 517
509 icalmemory_append_string(&str,&str_p,&buf_sz,recurmap[j].str); 518 icalmemory_append_string(&str,&str_p,&buf_sz,recurmap[j].str);
510 519
511 for(i=0; 520 for(i=0;
512 i< limit && array[i] != ICAL_RECURRENCE_ARRAY_MAX; 521 i< limit && array[i] != ICAL_RECURRENCE_ARRAY_MAX;
513 i++){ 522 i++){
514 if (j == 3) { /* BYDAY */ 523 if (j == 3) { /* BYDAY */
515 short dow = icalrecurrencetype_day_day_of_week(array[i]); 524 const char *daystr = icalrecur_weekday_to_string(
516 const char *daystr = icalrecur_weekday_to_string(dow); 525 icalrecurrencetype_day_day_of_week(array[i]));
517 short pos; 526 int pos;
518 527
519 pos = icalrecurrencetype_day_position(array[i]); 528 pos = icalrecurrencetype_day_position(array[i]);
520 529
521 if (pos == 0) 530 if (pos == 0)
522 icalmemory_append_string(&str,&str_p,&buf_sz,daystr); 531 icalmemory_append_string(&str,&str_p,&buf_sz,daystr);
523 else { 532 else {
524 sprintf(temp,"%d%s",pos,daystr); 533 sprintf(temp,"%d%s",pos,daystr);
525 icalmemory_append_string(&str,&str_p,&buf_sz,temp); 534 icalmemory_append_string(&str,&str_p,&buf_sz,temp);
526 } 535 }
527 536
528 } else { 537 } else {
529 sprintf(temp,"%d",array[i]); 538 sprintf(temp,"%d",array[i]);
530 icalmemory_append_string(&str,&str_p,&buf_sz, temp); 539 icalmemory_append_string(&str,&str_p,&buf_sz, temp);
531 } 540 }
532 541
533 if( (i+1)<limit &&array[i+1] 542 if( (i+1)<limit &&array[i+1]
534 != ICAL_RECURRENCE_ARRAY_MAX){ 543 != ICAL_RECURRENCE_ARRAY_MAX){
535 icalmemory_append_char(&str,&str_p,&buf_sz,','); 544 icalmemory_append_char(&str,&str_p,&buf_sz,',');
536 } 545 }
537 } 546 }
538 } 547 }
539 } 548 }
540 549
541 return str; 550 return str;
542} 551}
543#endif
544
545 552
546 553
547/************************* occurrence iteration routiens ******************/ 554/************************* occurrence iteration routiens ******************/
548 555
549enum byrule { 556enum byrule {
550 NO_CONTRACTION = -1, 557 NO_CONTRACTION = -1,
551 BY_SECOND = 0, 558 BY_SECOND = 0,
552 BY_MINUTE = 1, 559 BY_MINUTE = 1,
553 BY_HOUR = 2, 560 BY_HOUR = 2,
554 BY_DAY = 3, 561 BY_DAY = 3,
555 BY_MONTH_DAY = 4, 562 BY_MONTH_DAY = 4,
556 BY_YEAR_DAY = 5, 563 BY_YEAR_DAY = 5,
557 BY_WEEK_NO = 6, 564 BY_WEEK_NO = 6,
558 BY_MONTH = 7, 565 BY_MONTH = 7,
559 BY_SET_POS 566 BY_SET_POS
560}; 567};
561 568
562 569
563 570
564struct icalrecur_iterator_impl { 571struct icalrecur_iterator_impl {
565 572
566 struct icaltimetype dtstart; /* Hack. Make into time_t */ 573 struct icaltimetype dtstart; /* Hack. Make into time_t */
567 struct icaltimetype last; /* last time return from _iterator_next*/ 574 struct icaltimetype last; /* last time return from _iterator_next*/
568 int occurrence_no; /* number of step made on t iterator */ 575 int occurrence_no; /* number of step made on t iterator */
569 struct icalrecurrencetype rule; 576 struct icalrecurrencetype rule;
570 577
571 short days[366]; 578 short days[366];
572 short days_index; 579 short days_index;
573 580
574 enum byrule byrule; 581 enum byrule byrule;
575 short by_indices[9]; 582 short by_indices[9];
576 short orig_data[9]; /* 1 if there was data in the byrule */ 583 short orig_data[9]; /**< 1 if there was data in the byrule */
577 584
578 585
579 short *by_ptrs[9]; /* Pointers into the by_* array elements of the rule */ 586 short *by_ptrs[9]; /**< Pointers into the by_* array elements of the rule */
580 587
581}; 588};
582 589
590static void increment_year(icalrecur_iterator* impl, int inc);
591
583int icalrecur_iterator_sizeof_byarray(short* byarray) 592int icalrecur_iterator_sizeof_byarray(short* byarray)
584{ 593{
585 int array_itr; 594 int array_itr;
586 595
587 for(array_itr = 0; 596 for(array_itr = 0;
588 byarray[array_itr] != ICAL_RECURRENCE_ARRAY_MAX; 597 byarray[array_itr] != ICAL_RECURRENCE_ARRAY_MAX;
589 array_itr++){ 598 array_itr++){
590 } 599 }
591 600
592 return array_itr; 601 return array_itr;
593} 602}
594 603
595enum expand_table { 604enum expand_table {
596 UNKNOWN = 0, 605 UNKNOWN = 0,
597 CONTRACT = 1, 606 CONTRACT = 1,
598 EXPAND =2, 607 EXPAND =2,
599 ILLEGAL=3 608 ILLEGAL=3
600}; 609};
601 610
602/* The split map indicates, for a particular interval, wether a BY_* 611/**
603 rule part expands the number of instances in the occcurrence set or 612 * The split map indicates, for a particular interval, wether a BY_*
604 contracts it. 1=> contract, 2=>expand, and 3 means the pairing is 613 * rule part expands the number of instances in the occcurrence set or
605 not allowed. */ 614 * contracts it. 1=> contract, 2=>expand, and 3 means the pairing is
615 * not allowed.
616 */
617
606struct expand_split_map_struct 618struct expand_split_map_struct
607{ 619{
608 icalrecurrencetype_frequency frequency; 620 icalrecurrencetype_frequency frequency;
609 621
610 /* Elements of the 'map' array correspond to the BYxxx rules: 622 /* Elements of the 'map' array correspond to the BYxxx rules:
611 Second,Minute,Hour,Day,Month Day,Year Day,Week No,Month*/ 623 Second,Minute,Hour,Day,Month Day,Year Day,Week No,Month*/
612 624
613 short map[8]; 625 short map[8];
614}; 626};
615 627
616struct expand_split_map_struct expand_map[] = 628static struct expand_split_map_struct expand_map[] =
617{ 629{
618 {ICAL_SECONDLY_RECURRENCE,{1,1,1,1,1,1,1,1}}, 630 {ICAL_SECONDLY_RECURRENCE,{1,1,1,1,1,1,1,1}},
619 {ICAL_MINUTELY_RECURRENCE,{2,1,1,1,1,1,1,1}}, 631 {ICAL_MINUTELY_RECURRENCE,{2,1,1,1,1,1,1,1}},
620 {ICAL_HOURLY_RECURRENCE, {2,2,1,1,1,1,1,1}}, 632 {ICAL_HOURLY_RECURRENCE, {2,2,1,1,1,1,1,1}},
621 {ICAL_DAILY_RECURRENCE, {2,2,2,1,1,1,1,1}}, 633 {ICAL_DAILY_RECURRENCE, {2,2,2,1,1,1,1,1}},
622 {ICAL_WEEKLY_RECURRENCE, {2,2,2,2,3,3,1,1}}, 634 {ICAL_WEEKLY_RECURRENCE, {2,2,2,2,3,3,1,1}},
623 {ICAL_MONTHLY_RECURRENCE, {2,2,2,2,2,3,3,1}}, 635 {ICAL_MONTHLY_RECURRENCE, {2,2,2,2,2,3,3,1}},
624 {ICAL_YEARLY_RECURRENCE, {2,2,2,2,2,2,2,2}}, 636 {ICAL_YEARLY_RECURRENCE, {2,2,2,2,2,2,2,2}},
625 {ICAL_NO_RECURRENCE, {0,0,0,0,0,0,0,0}} 637 {ICAL_NO_RECURRENCE, {0,0,0,0,0,0,0,0}}
626 638
627}; 639};
628 640
629 641
630 642
631/* Check that the rule has only the two given interday byrule parts. */ 643/** Check that the rule has only the two given interday byrule parts. */
632int icalrecur_two_byrule(struct icalrecur_iterator_impl* impl, 644static
645int icalrecur_two_byrule(icalrecur_iterator* impl,
633 enum byrule one,enum byrule two) 646 enum byrule one,enum byrule two)
634{ 647{
635 short test_array[9]; 648 short test_array[9];
636 enum byrule itr; 649 enum byrule itr;
637 int passes = 0; 650 int passes = 0;
638 651
639 memset(test_array,0,9); 652 memset(test_array,0,sizeof(test_array));
640 653
641 test_array[one] = 1; 654 test_array[one] = 1;
642 test_array[two] = 1; 655 test_array[two] = 1;
643 656
644 for(itr = BY_DAY; itr != BY_SET_POS; itr++){ 657 for(itr = BY_DAY; itr != BY_SET_POS; itr++){
645 658
646 if( (test_array[itr] == 0 && 659 if( (test_array[itr] == 0 &&
647 impl->by_ptrs[itr][0] != ICAL_RECURRENCE_ARRAY_MAX 660 impl->by_ptrs[itr][0] != ICAL_RECURRENCE_ARRAY_MAX
648 ) || 661 ) ||
649 (test_array[itr] == 1 && 662 (test_array[itr] == 1 &&
650 impl->by_ptrs[itr][0] == ICAL_RECURRENCE_ARRAY_MAX 663 impl->by_ptrs[itr][0] == ICAL_RECURRENCE_ARRAY_MAX
651 ) 664 )
652 ) { 665 ) {
653 /* test failed */ 666 /* test failed */
654 passes = 0; 667 passes = 0;
655 } 668 }
656 } 669 }
657 670
658 return passes; 671 return passes;
659 672
660} 673}
661 674
662/* Check that the rule has only the one given interdat byrule parts. */ 675/** Check that the rule has only the one given interdat byrule parts. */
663int icalrecur_one_byrule(struct icalrecur_iterator_impl* impl,enum byrule one) 676static int icalrecur_one_byrule(icalrecur_iterator* impl,enum byrule one)
664{ 677{
665 int passes = 1; 678 int passes = 1;
666 enum byrule itr; 679 enum byrule itr;
667 680
668 for(itr = BY_DAY; itr != BY_SET_POS; itr++){ 681 for(itr = BY_DAY; itr != BY_SET_POS; itr++){
669 682
670 if ((itr==one && impl->by_ptrs[itr][0] == ICAL_RECURRENCE_ARRAY_MAX) || 683 if ((itr==one && impl->by_ptrs[itr][0] == ICAL_RECURRENCE_ARRAY_MAX) ||
671 (itr!=one && impl->by_ptrs[itr][0] != ICAL_RECURRENCE_ARRAY_MAX)) { 684 (itr!=one && impl->by_ptrs[itr][0] != ICAL_RECURRENCE_ARRAY_MAX)) {
672 passes = 0; 685 passes = 0;
673 } 686 }
674 } 687 }
675 688
676 return passes; 689 return passes;
677} 690}
678 691
679int count_byrules(struct icalrecur_iterator_impl* impl) 692static int count_byrules(icalrecur_iterator* impl)
680{ 693{
681 int count = 0; 694 int count = 0;
682 enum byrule itr; 695 enum byrule itr;
683 696
684 for(itr = BY_DAY; itr <= BY_SET_POS; itr++){ 697 for(itr = BY_DAY; itr <= BY_SET_POS; itr++){
685 if(impl->by_ptrs[itr][0] != ICAL_RECURRENCE_ARRAY_MAX){ 698 if(impl->by_ptrs[itr][0] != ICAL_RECURRENCE_ARRAY_MAX){
686 count++; 699 count++;
687 } 700 }
688 } 701 }
689 702
690 return count; 703 return count;
691} 704}
692 705
693 706
694void setup_defaults(struct icalrecur_iterator_impl* impl, 707static void setup_defaults(icalrecur_iterator* impl,
695 enum byrule byrule, icalrecurrencetype_frequency req, 708 enum byrule byrule, icalrecurrencetype_frequency req,
696 short deftime, int *timepart) 709 int deftime, int *timepart)
697{ 710{
698 711
699 icalrecurrencetype_frequency freq; 712 icalrecurrencetype_frequency freq;
700 freq = impl->rule.freq; 713 freq = impl->rule.freq;
701 714
702 /* Re-write the BY rule arrays with data from the DTSTART time so 715 /* Re-write the BY rule arrays with data from the DTSTART time so
703 we don't have to explicitly deal with DTSTART */ 716 we don't have to explicitly deal with DTSTART */
704 717
705 if(impl->by_ptrs[byrule][0] == ICAL_RECURRENCE_ARRAY_MAX && 718 if(impl->by_ptrs[byrule][0] == ICAL_RECURRENCE_ARRAY_MAX &&
706 expand_map[freq].map[byrule] != CONTRACT){ 719 expand_map[freq].map[byrule] != CONTRACT){
707 impl->by_ptrs[byrule][0] = deftime; 720 impl->by_ptrs[byrule][0] = (short)deftime;
708 } 721 }
709 722
710 /* Initialize the first occurence */ 723 /* Initialize the first occurence */
711 if( freq != req && expand_map[freq].map[byrule] != CONTRACT){ 724 if( freq != req && expand_map[freq].map[byrule] != CONTRACT){
712 *timepart = impl->by_ptrs[byrule][0]; 725 *timepart = impl->by_ptrs[byrule][0];
713 } 726 }
714 727
715 728
716} 729}
717 730
718int has_by_data(struct icalrecur_iterator_impl* impl, enum byrule byrule){ 731static int has_by_data(icalrecur_iterator* impl, enum byrule byrule){
719 732
720 return (impl->orig_data[byrule] == 1); 733 return (impl->orig_data[byrule] == 1);
721} 734}
722 735
723 736
724int expand_year_days(struct icalrecur_iterator_impl* impl,short year); 737static int expand_year_days(icalrecur_iterator* impl, int year);
725 738
726 739
727icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule, 740icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
728 struct icaltimetype dtstart) 741 struct icaltimetype dtstart)
729{ 742{
730 struct icalrecur_iterator_impl* impl; 743 icalrecur_iterator* impl;
731 icalrecurrencetype_frequency freq; 744 icalrecurrencetype_frequency freq;
732 745
733 short days_in_month; 746 if ( ( impl = (icalrecur_iterator*)
734 747 malloc(sizeof(icalrecur_iterator))) == 0) {
735 if ( ( impl = (struct icalrecur_iterator_impl *)
736 malloc(sizeof(struct icalrecur_iterator_impl))) == 0) {
737 icalerror_set_errno(ICAL_NEWFAILED_ERROR); 748 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
738 return 0; 749 return 0;
739 } 750 }
740 751
741 memset(impl,0,sizeof(struct icalrecur_iterator_impl)); 752 memset(impl,0,sizeof(icalrecur_iterator));
742 753
743 impl->rule = rule; 754 impl->rule = rule;
744 impl->last = dtstart; 755 impl->last = dtstart;
745 impl->dtstart = dtstart; 756 impl->dtstart = dtstart;
746 impl->days_index =0; 757 impl->days_index =0;
747 impl->occurrence_no = 0; 758 impl->occurrence_no = 0;
748 freq = impl->rule.freq; 759 freq = impl->rule.freq;
749 760
750 /* Set up convienience pointers to make the code simpler. Allows 761 /* Set up convienience pointers to make the code simpler. Allows
751 us to iterate through all of the BY* arrays in the rule. */ 762 us to iterate through all of the BY* arrays in the rule. */
752 763
753 impl->by_ptrs[BY_MONTH]=impl->rule.by_month; 764 impl->by_ptrs[BY_MONTH]=impl->rule.by_month;
754 impl->by_ptrs[BY_WEEK_NO]=impl->rule.by_week_no; 765 impl->by_ptrs[BY_WEEK_NO]=impl->rule.by_week_no;
755 impl->by_ptrs[BY_YEAR_DAY]=impl->rule.by_year_day; 766 impl->by_ptrs[BY_YEAR_DAY]=impl->rule.by_year_day;
756 impl->by_ptrs[BY_MONTH_DAY]=impl->rule.by_month_day; 767 impl->by_ptrs[BY_MONTH_DAY]=impl->rule.by_month_day;
757 impl->by_ptrs[BY_DAY]=impl->rule.by_day; 768 impl->by_ptrs[BY_DAY]=impl->rule.by_day;
758 impl->by_ptrs[BY_HOUR]=impl->rule.by_hour; 769 impl->by_ptrs[BY_HOUR]=impl->rule.by_hour;
759 impl->by_ptrs[BY_MINUTE]=impl->rule.by_minute; 770 impl->by_ptrs[BY_MINUTE]=impl->rule.by_minute;
760 impl->by_ptrs[BY_SECOND]=impl->rule.by_second; 771 impl->by_ptrs[BY_SECOND]=impl->rule.by_second;
761 impl->by_ptrs[BY_SET_POS]=impl->rule.by_set_pos; 772 impl->by_ptrs[BY_SET_POS]=impl->rule.by_set_pos;
762 773
763 memset(impl->orig_data,0,9); 774 memset(impl->orig_data,0,9*sizeof(short));
764 775
765 /* Note which by rules had data in them when the iterator was 776 /* Note which by rules had data in them when the iterator was
766 created. We can't use the actuall by_x arrays, because the 777 created. We can't use the actuall by_x arrays, because the
767 empty ones will be given default values later in this 778 empty ones will be given default values later in this
768 routine. The orig_data array will be used later in has_by_data */ 779 routine. The orig_data array will be used later in has_by_data */
769 780
770 impl->orig_data[BY_MONTH] 781 impl->orig_data[BY_MONTH]
771 = (impl->rule.by_month[0]!=ICAL_RECURRENCE_ARRAY_MAX); 782 = (short)(impl->rule.by_month[0]!=ICAL_RECURRENCE_ARRAY_MAX);
772 impl->orig_data[BY_WEEK_NO] 783 impl->orig_data[BY_WEEK_NO]
773 =(impl->rule.by_week_no[0]!=ICAL_RECURRENCE_ARRAY_MAX); 784 =(short)(impl->rule.by_week_no[0]!=ICAL_RECURRENCE_ARRAY_MAX);
774 impl->orig_data[BY_YEAR_DAY] 785 impl->orig_data[BY_YEAR_DAY]
775 =(impl->rule.by_year_day[0]!=ICAL_RECURRENCE_ARRAY_MAX); 786 =(short)(impl->rule.by_year_day[0]!=ICAL_RECURRENCE_ARRAY_MAX);
776 impl->orig_data[BY_MONTH_DAY] 787 impl->orig_data[BY_MONTH_DAY]
777 =(impl->rule.by_month_day[0]!=ICAL_RECURRENCE_ARRAY_MAX); 788 =(short)(impl->rule.by_month_day[0]!=ICAL_RECURRENCE_ARRAY_MAX);
778 impl->orig_data[BY_DAY] 789 impl->orig_data[BY_DAY]
779 = (impl->rule.by_day[0]!=ICAL_RECURRENCE_ARRAY_MAX); 790 = (short)(impl->rule.by_day[0]!=ICAL_RECURRENCE_ARRAY_MAX);
780 impl->orig_data[BY_HOUR] 791 impl->orig_data[BY_HOUR]
781 = (impl->rule.by_hour[0]!=ICAL_RECURRENCE_ARRAY_MAX); 792 = (short)(impl->rule.by_hour[0]!=ICAL_RECURRENCE_ARRAY_MAX);
782 impl->orig_data[BY_MINUTE] 793 impl->orig_data[BY_MINUTE]
783 = (impl->rule.by_minute[0]!=ICAL_RECURRENCE_ARRAY_MAX); 794 = (short)(impl->rule.by_minute[0]!=ICAL_RECURRENCE_ARRAY_MAX);
784 impl->orig_data[BY_SECOND] 795 impl->orig_data[BY_SECOND]
785 = (impl->rule.by_second[0]!=ICAL_RECURRENCE_ARRAY_MAX); 796 = (short)(impl->rule.by_second[0]!=ICAL_RECURRENCE_ARRAY_MAX);
786 impl->orig_data[BY_SET_POS] 797 impl->orig_data[BY_SET_POS]
787 = (impl->rule.by_set_pos[0]!=ICAL_RECURRENCE_ARRAY_MAX); 798 = (short)(impl->rule.by_set_pos[0]!=ICAL_RECURRENCE_ARRAY_MAX);
788 799
789 800
790 /* Check if the recurrence rule is legal */ 801 /* Check if the recurrence rule is legal */
791 802
792 /* If the BYYEARDAY appears, no other date rule part may appear. */ 803 /* If the BYYEARDAY appears, no other date rule part may appear. */
793 804
794 if(icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_MONTH) || 805 if(icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_MONTH) ||
795 icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_WEEK_NO) || 806 icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_WEEK_NO) ||
796 icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_MONTH_DAY) || 807 icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_MONTH_DAY) ||
797 icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_DAY) ){ 808 icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_DAY) ){
798 809
799 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 810 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
800 811
801 return 0; 812 return 0;
802 } 813 }
803 814
804 /* BYWEEKNO and BYMONTH rule parts may not both appear.*/ 815 /* BYWEEKNO and BYMONTH rule parts may not both appear.*/
805 816
806 if(icalrecur_two_byrule(impl,BY_WEEK_NO,BY_MONTH)){ 817 if(icalrecur_two_byrule(impl,BY_WEEK_NO,BY_MONTH)){
807 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 818 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
808 819
809 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 820 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
810 return 0; 821 return 0;
811 } 822 }
@@ -831,1485 +842,1551 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
831 842
832 843
833 /*For WEEKLY recurrences (FREQ=WEEKLY) neither BYMONTHDAY nor 844 /*For WEEKLY recurrences (FREQ=WEEKLY) neither BYMONTHDAY nor
834 BYYEARDAY may appear. */ 845 BYYEARDAY may appear. */
835 846
836 if(freq == ICAL_WEEKLY_RECURRENCE && 847 if(freq == ICAL_WEEKLY_RECURRENCE &&
837 icalrecur_one_byrule(impl,BY_MONTH_DAY )) { 848 icalrecur_one_byrule(impl,BY_MONTH_DAY )) {
838 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 849 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
839 return 0; 850 return 0;
840 } 851 }
841 852
842 /* BYYEARDAY may only appear in YEARLY rules */ 853 /* BYYEARDAY may only appear in YEARLY rules */
843 if(freq != ICAL_YEARLY_RECURRENCE && 854 if(freq != ICAL_YEARLY_RECURRENCE &&
844 icalrecur_one_byrule(impl,BY_YEAR_DAY )) { 855 icalrecur_one_byrule(impl,BY_YEAR_DAY )) {
845 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 856 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
846 return 0; 857 return 0;
847 } 858 }
848 859
849 /* Rewrite some of the rules and set up defaults to make later 860 /* Rewrite some of the rules and set up defaults to make later
850 processing easier. Primarily, t involves copying an element 861 processing easier. Primarily, t involves copying an element
851 from the start time into the coresponding BY_* array when the 862 from the start time into the coresponding BY_* array when the
852 BY_* array is empty */ 863 BY_* array is empty */
853 864
854 865
855 setup_defaults(impl,BY_SECOND,ICAL_SECONDLY_RECURRENCE,impl->dtstart.second, 866 setup_defaults(impl,BY_SECOND,ICAL_SECONDLY_RECURRENCE,
867 impl->dtstart.second,
856 &(impl->last.second)); 868 &(impl->last.second));
857 869
858 setup_defaults(impl,BY_MINUTE,ICAL_MINUTELY_RECURRENCE,impl->dtstart.minute, 870 setup_defaults(impl,BY_MINUTE,ICAL_MINUTELY_RECURRENCE,
871 impl->dtstart.minute,
859 &(impl->last.minute)); 872 &(impl->last.minute));
860 873
861 setup_defaults(impl,BY_HOUR,ICAL_HOURLY_RECURRENCE,impl->dtstart.hour, 874 setup_defaults(impl,BY_HOUR,ICAL_HOURLY_RECURRENCE,
875 impl->dtstart.hour,
862 &(impl->last.hour)); 876 &(impl->last.hour));
863 877
864 setup_defaults(impl,BY_MONTH_DAY,ICAL_DAILY_RECURRENCE,impl->dtstart.day, 878 setup_defaults(impl,BY_MONTH_DAY,ICAL_DAILY_RECURRENCE,
879 impl->dtstart.day,
865 &(impl->last.day)); 880 &(impl->last.day));
866 881
867 setup_defaults(impl,BY_MONTH,ICAL_MONTHLY_RECURRENCE,impl->dtstart.month, 882 setup_defaults(impl,BY_MONTH,ICAL_MONTHLY_RECURRENCE,
883 impl->dtstart.month,
868 &(impl->last.month)); 884 &(impl->last.month));
869 885
870 886
871 if(impl->rule.freq == ICAL_WEEKLY_RECURRENCE ){ 887 if(impl->rule.freq == ICAL_WEEKLY_RECURRENCE ){
872 888
873 if(impl->by_ptrs[BY_DAY][0] == ICAL_RECURRENCE_ARRAY_MAX){ 889 if(impl->by_ptrs[BY_DAY][0] == ICAL_RECURRENCE_ARRAY_MAX){
874 890
875 /* Weekly recurrences with no BY_DAY data should occur on the 891 /* Weekly recurrences with no BY_DAY data should occur on the
876 same day of the week as the start time . */ 892 same day of the week as the start time . */
877 impl->by_ptrs[BY_DAY][0] = icaltime_day_of_week(impl->dtstart); 893 impl->by_ptrs[BY_DAY][0] = (short)icaltime_day_of_week(impl->dtstart);
878 894
879 } else { 895 } else {
880 /* If there is BY_DAY data, then we need to move the initial 896 /* If there is BY_DAY data, then we need to move the initial
881 time to the start of the BY_DAY data. That is if the 897 time to the start of the BY_DAY data. That is if the
882 start time is on a Wednesday, and the rule has 898 start time is on a Wednesday, and the rule has
883 BYDAY=MO,WE,FR, move the initial time back to 899 BYDAY=MO,WE,FR, move the initial time back to
884 monday. Otherwise, jumping to the next week ( jumping 7 900 monday. Otherwise, jumping to the next week ( jumping 7
885 days ahead ) will skip over some occurrences in the 901 days ahead ) will skip over some occurrences in the
886 second week. */ 902 second week. */
887 903
888 /* This is probably a HACK. There should be some more 904 /* This is probably a HACK. There should be some more
889 general way to solve this problem */ 905 general way to solve this problem */
890 906
891 short dow = impl->by_ptrs[BY_DAY][0]-icaltime_day_of_week(impl->last); 907 short dow = (short)(impl->by_ptrs[BY_DAY][0]-icaltime_day_of_week(impl->last));
892 908
893 if(dow < 0) { 909 if(dow < 0) {
894 /* initial time is after first day of BY_DAY data */ 910 /* initial time is after first day of BY_DAY data */
895 911
896 impl->last.day += dow; 912 impl->last.day += dow;
897 impl->last = icaltime_normalize(impl->last); 913 impl->last = icaltime_normalize(impl->last);
898 } 914 }
899 } 915 }
900 916
901 917
902 } 918 }
903 919
904 /* For YEARLY rule, begin by setting up the year days array */ 920 /* For YEARLY rule, begin by setting up the year days array . The
921 YEARLY rules work by expanding one year at a time. */
905 922
906 if(impl->rule.freq == ICAL_YEARLY_RECURRENCE){ 923 if(impl->rule.freq == ICAL_YEARLY_RECURRENCE){
924 struct icaltimetype next;
925
926 for (;;) {
907 expand_year_days(impl,impl->last.year); 927 expand_year_days(impl,impl->last.year);
928 if (impl->days[0] != ICAL_RECURRENCE_ARRAY_MAX)
929 break; /* break when no days are expanded */
930 increment_year(impl,impl->rule.interval);
931 }
932
933 /* Copy the first day into last. */
934 next = icaltime_from_day_of_year(impl->days[0], impl->last.year);
935
936 impl->last.day = next.day;
937 impl->last.month = next.month;
908 } 938 }
909 939
910 940
911 /* If this is a monthly interval with by day data, then we need to 941 /* If this is a monthly interval with by day data, then we need to
912 set the last value to the appropriate day of the month */ 942 set the last value to the appropriate day of the month */
913 943
914 if(impl->rule.freq == ICAL_MONTHLY_RECURRENCE && 944 if(impl->rule.freq == ICAL_MONTHLY_RECURRENCE &&
915 has_by_data(impl,BY_DAY)) { 945 has_by_data(impl,BY_DAY)) {
916 946
917 short dow = icalrecurrencetype_day_day_of_week( 947 int dow = icalrecurrencetype_day_day_of_week(
918 impl->by_ptrs[BY_DAY][impl->by_indices[BY_DAY]]); 948 impl->by_ptrs[BY_DAY][impl->by_indices[BY_DAY]]);
919 short pos = icalrecurrencetype_day_position( 949 int pos = icalrecurrencetype_day_position(
920 impl->by_ptrs[BY_DAY][impl->by_indices[BY_DAY]]); 950 impl->by_ptrs[BY_DAY][impl->by_indices[BY_DAY]]);
921 951
922 short poscount = 0; 952 int poscount = 0;
923 days_in_month = 953 int days_in_month =
924 icaltime_days_in_month(impl->last.month, impl->last.year); 954 icaltime_days_in_month(impl->last.month, impl->last.year);
925 955
926 if(pos >= 0){ 956 if(pos >= 0){
927 /* Count up from the first day pf the month to find the 957 /* Count up from the first day pf the month to find the
928 pos'th weekday of dow ( like the second monday. ) */ 958 pos'th weekday of dow ( like the second monday. ) */
929 959
930 for(impl->last.day = 1; 960 for(impl->last.day = 1;
931 impl->last.day <= days_in_month; 961 impl->last.day <= days_in_month;
932 impl->last.day++){ 962 impl->last.day++){
933 963
934 if(icaltime_day_of_week(impl->last) == dow){ 964 if(icaltime_day_of_week(impl->last) == dow){
935 if(++poscount == pos || pos == 0){ 965 if(++poscount == pos || pos == 0){
936 break; 966 break;
937 } 967 }
938 } 968 }
939 } 969 }
940 } else { 970 } else {
941 /* Count down from the last day pf the month to find the 971 /* Count down from the last day pf the month to find the
942 pos'th weekday of dow ( like the second to last monday. ) */ 972 pos'th weekday of dow ( like the second to last monday. ) */
943 pos = -pos; 973 pos = -pos;
944 for(impl->last.day = days_in_month; 974 for(impl->last.day = days_in_month;
945 impl->last.day != 0; 975 impl->last.day != 0;
946 impl->last.day--){ 976 impl->last.day--){
947 977
948 if(icaltime_day_of_week(impl->last) == dow){ 978 if(icaltime_day_of_week(impl->last) == dow){
949 if(++poscount == pos ){ 979 if(++poscount == pos ){
950 break; 980 break;
951 } 981 }
952 } 982 }
953 } 983 }
954 } 984 }
955 985
956 986
957 if(impl->last.day > days_in_month || impl->last.day == 0){ 987 if(impl->last.day > days_in_month || impl->last.day == 0){
958 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 988 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
959 return 0; 989 return 0;
960 } 990 }
961 991
962 } 992 }
963 993
964 994
965 995
966 return impl; 996 return impl;
967} 997}
968 998
969 999
970void icalrecur_iterator_free(icalrecur_iterator* i) 1000void icalrecur_iterator_free(icalrecur_iterator* i)
971{ 1001{
1002 icalerror_check_arg_rv((i!=0),"impl");
972 1003
973 struct icalrecur_iterator_impl* impl = 1004 free(i);
974 (struct icalrecur_iterator_impl*)i;
975
976 icalerror_check_arg_rv((impl!=0),"impl");
977
978 free(impl);
979 1005
980} 1006}
981 1007
982 1008static void increment_year(icalrecur_iterator* impl, int inc)
983void increment_year(struct icalrecur_iterator_impl* impl, int inc)
984{ 1009{
985 impl->last.year+=inc; 1010 impl->last.year+=inc;
986} 1011}
987 1012
988/* Increment month is different that the other incement_* routines -- 1013/** Increment month is different that the other incement_* routines --
989 it figures out the interval for itself, and uses BYMONTH data if 1014 it figures out the interval for itself, and uses BYMONTH data if
990 available. */ 1015 available. */
991void increment_month(struct icalrecur_iterator_impl* impl) 1016static void increment_month(icalrecur_iterator* impl)
992{ 1017{
993 int years; 1018 int years;
994 1019
995 if(has_by_data(impl,BY_MONTH) ){ 1020 if(has_by_data(impl,BY_MONTH) ){
996 /* Ignore the frequency and use the byrule data */ 1021 /* Ignore the frequency and use the byrule data */
997 1022
998 impl->by_indices[BY_MONTH]++; 1023 impl->by_indices[BY_MONTH]++;
999 1024
1000 if (impl->by_ptrs[BY_MONTH][impl->by_indices[BY_MONTH]] 1025 if (impl->by_ptrs[BY_MONTH][impl->by_indices[BY_MONTH]]
1001 ==ICAL_RECURRENCE_ARRAY_MAX){ 1026 ==ICAL_RECURRENCE_ARRAY_MAX){
1002 impl->by_indices[BY_MONTH] = 0; 1027 impl->by_indices[BY_MONTH] = 0;
1003 1028
1004 increment_year(impl,1); 1029 increment_year(impl,1);
1005 1030
1006 } 1031 }
1007 1032
1008 impl->last.month = 1033 impl->last.month =
1009 impl->by_ptrs[BY_MONTH][impl->by_indices[BY_MONTH]]; 1034 impl->by_ptrs[BY_MONTH][impl->by_indices[BY_MONTH]];
1010 1035
1011 } else { 1036 } else {
1012 1037
1013 int inc; 1038 int inc;
1014 1039
1015 if(impl->rule.freq == ICAL_MONTHLY_RECURRENCE){ 1040 if(impl->rule.freq == ICAL_MONTHLY_RECURRENCE){
1016 inc = impl->rule.interval; 1041 inc = impl->rule.interval;
1017 } else { 1042 } else {
1018 inc = 1; 1043 inc = 1;
1019 } 1044 }
1020 1045
1021 impl->last.month+=inc; 1046 impl->last.month+=inc;
1022 1047
1023 /* Months are offset by one */ 1048 /* Months are offset by one */
1024 impl->last.month--; 1049 impl->last.month--;
1025 1050
1026 years = impl->last.month / 12; 1051 years = impl->last.month / 12;
1027 1052
1028 impl->last.month = impl->last.month % 12; 1053 impl->last.month = impl->last.month % 12;
1029 1054
1030 impl->last.month++; 1055 impl->last.month++;
1031 1056
1032 if (years != 0){ 1057 if (years != 0){
1033 increment_year(impl,years); 1058 increment_year(impl,years);
1034 } 1059 }
1035 } 1060 }
1036} 1061}
1037 1062
1038void increment_monthday(struct icalrecur_iterator_impl* impl, int inc) 1063static void increment_monthday(icalrecur_iterator* impl, int inc)
1039{ 1064{
1040 int i; 1065 int i;
1041 1066
1042 for(i=0; i<inc; i++){ 1067 for(i=0; i<inc; i++){
1043 1068
1044 short days_in_month = 1069 int days_in_month =
1045 icaltime_days_in_month(impl->last.month,impl->last.year); 1070 icaltime_days_in_month(impl->last.month,impl->last.year);
1046 1071
1047 impl->last.day++; 1072 impl->last.day++;
1048 1073
1049 if (impl->last.day > days_in_month){ 1074 if (impl->last.day > days_in_month){
1050 impl->last.day = impl->last.day-days_in_month; 1075 impl->last.day = impl->last.day-days_in_month;
1051 increment_month(impl); 1076 increment_month(impl);
1052 } 1077 }
1053 } 1078 }
1054} 1079}
1055 1080
1056 1081
1057void increment_hour(struct icalrecur_iterator_impl* impl, int inc) 1082static void increment_hour(icalrecur_iterator* impl, int inc)
1058{ 1083{
1059 short days; 1084 int days;
1060 1085
1061 impl->last.hour+=inc; 1086 impl->last.hour+=inc;
1062 1087
1063 days = impl->last.hour / 24; 1088 days = impl->last.hour / 24;
1064 impl->last.hour = impl->last.hour % 24; 1089 impl->last.hour = impl->last.hour % 24;
1065 1090
1066 if (impl->days != 0){ 1091 if (impl->days != 0){
1067 increment_monthday(impl,days); 1092 increment_monthday(impl,days);
1068 } 1093 }
1069} 1094}
1070 1095
1071void increment_minute(struct icalrecur_iterator_impl* impl, int inc) 1096static void increment_minute(icalrecur_iterator* impl, int inc)
1072{ 1097{
1073 short hours; 1098 int hours;
1074 1099
1075 impl->last.minute+=inc; 1100 impl->last.minute+=inc;
1076 1101
1077 hours = impl->last.minute / 60; 1102 hours = impl->last.minute / 60;
1078 impl->last.minute = impl->last.minute % 60; 1103 impl->last.minute = impl->last.minute % 60;
1079 1104
1080 if (hours != 0){ 1105 if (hours != 0){
1081 increment_hour(impl,hours); 1106 increment_hour(impl,hours);
1082 } 1107 }
1083 1108
1084} 1109}
1085 1110
1086void increment_second(struct icalrecur_iterator_impl* impl, int inc) 1111static void increment_second(icalrecur_iterator* impl, int inc)
1087{ 1112{
1088 short minutes; 1113 int minutes;
1089 1114
1090 impl->last.second+=inc; 1115 impl->last.second+=inc;
1091 1116
1092 minutes = impl->last.second / 60; 1117 minutes = impl->last.second / 60;
1093 impl->last.second = impl->last.second % 60; 1118 impl->last.second = impl->last.second % 60;
1094 1119
1095 if (minutes != 0) 1120 if (minutes != 0)
1096 { 1121 {
1097 increment_minute(impl, minutes); 1122 increment_minute(impl, minutes);
1098 } 1123 }
1099} 1124}
1100 1125
1101#if 0 1126#if 0
1102#include "ical.h" 1127#include "ical.h"
1103void test_increment() 1128void test_increment()
1104{ 1129{
1105 struct icalrecur_iterator_impl impl; 1130 icalrecur_iterator impl;
1106 1131
1107 impl.last = icaltime_from_string("20000101T000000Z"); 1132 impl.last = icaltime_from_string("20000101T000000Z");
1108 1133
1109 printf("Orig: %s\n",icaltime_as_ctime(impl.last)); 1134 printf("Orig: %s\n",icaltime_as_ctime(impl.last));
1110 1135
1111 increment_second(&impl,5); 1136 increment_second(&impl,5);
1112 printf("+ 5 sec : %s\n",icaltime_as_ctime(impl.last)); 1137 printf("+ 5 sec : %s\n",icaltime_as_ctime(impl.last));
1113 1138
1114 increment_second(&impl,355); 1139 increment_second(&impl,355);
1115 printf("+ 355 sec : %s\n",icaltime_as_ctime(impl.last)); 1140 printf("+ 355 sec : %s\n",icaltime_as_ctime(impl.last));
1116 1141
1117 increment_minute(&impl,5); 1142 increment_minute(&impl,5);
1118 printf("+ 5 min : %s\n",icaltime_as_ctime(impl.last)); 1143 printf("+ 5 min : %s\n",icaltime_as_ctime(impl.last));
1119 1144
1120 increment_minute(&impl,360); 1145 increment_minute(&impl,360);
1121 printf("+ 360 min : %s\n",icaltime_as_ctime(impl.last)); 1146 printf("+ 360 min : %s\n",icaltime_as_ctime(impl.last));
1122 increment_hour(&impl,5); 1147 increment_hour(&impl,5);
1123 printf("+ 5 hours : %s\n",icaltime_as_ctime(impl.last)); 1148 printf("+ 5 hours : %s\n",icaltime_as_ctime(impl.last));
1124 increment_hour(&impl,43); 1149 increment_hour(&impl,43);
1125 printf("+ 43 hours : %s\n",icaltime_as_ctime(impl.last)); 1150 printf("+ 43 hours : %s\n",icaltime_as_ctime(impl.last));
1126 increment_monthday(&impl,3); 1151 increment_monthday(&impl,3);
1127 printf("+ 3 days : %s\n",icaltime_as_ctime(impl.last)); 1152 printf("+ 3 days : %s\n",icaltime_as_ctime(impl.last));
1128 increment_monthday(&impl,600); 1153 increment_monthday(&impl,600);
1129 printf("+ 600 days : %s\n",icaltime_as_ctime(impl.last)); 1154 printf("+ 600 days : %s\n",icaltime_as_ctime(impl.last));
1130 1155
1131} 1156}
1132 1157
1133#endif 1158#endif
1134 1159
1135short next_second(struct icalrecur_iterator_impl* impl) 1160static int next_second(icalrecur_iterator* impl)
1136{ 1161{
1137 1162
1138 short has_by_data = (impl->by_ptrs[BY_SECOND][0]!=ICAL_RECURRENCE_ARRAY_MAX); 1163 int has_by_second = (impl->by_ptrs[BY_SECOND][0]!=ICAL_RECURRENCE_ARRAY_MAX);
1139 short this_frequency = (impl->rule.freq == ICAL_SECONDLY_RECURRENCE); 1164 int this_frequency = (impl->rule.freq == ICAL_SECONDLY_RECURRENCE);
1140 1165
1141 short end_of_data = 0; 1166 int end_of_data = 0;
1142 1167
1143 assert(has_by_data || this_frequency); 1168 assert(has_by_second || this_frequency);
1144 1169
1145 if( has_by_data ){ 1170 if( has_by_second ){
1146 /* Ignore the frequency and use the byrule data */ 1171 /* Ignore the frequency and use the byrule data */
1147 1172
1148 impl->by_indices[BY_SECOND]++; 1173 impl->by_indices[BY_SECOND]++;
1149 1174
1150 if (impl->by_ptrs[BY_SECOND][impl->by_indices[BY_SECOND]] 1175 if (impl->by_ptrs[BY_SECOND][impl->by_indices[BY_SECOND]]
1151 ==ICAL_RECURRENCE_ARRAY_MAX){ 1176 ==ICAL_RECURRENCE_ARRAY_MAX){
1152 impl->by_indices[BY_SECOND] = 0; 1177 impl->by_indices[BY_SECOND] = 0;
1153 1178
1154 end_of_data = 1; 1179 end_of_data = 1;
1155 } 1180 }
1156 1181
1157 1182
1158 impl->last.second = 1183 impl->last.second =
1159 impl->by_ptrs[BY_SECOND][impl->by_indices[BY_SECOND]]; 1184 impl->by_ptrs[BY_SECOND][impl->by_indices[BY_SECOND]];
1160 1185
1161 1186
1162 } else if( !has_by_data && this_frequency ){ 1187 } else if( !has_by_second && this_frequency ){
1163 /* Compute the next value from the last time and the frequency interval*/ 1188 /* Compute the next value from the last time and the frequency interval*/
1164 increment_second(impl, impl->rule.interval); 1189 increment_second(impl, impl->rule.interval);
1165 1190
1166 } 1191 }
1167 1192
1168 /* If we have gone through all of the seconds on the BY list, then we 1193 /* If we have gone through all of the seconds on the BY list, then we
1169 need to move to the next minute */ 1194 need to move to the next minute */
1170 1195
1171 if(has_by_data && end_of_data && this_frequency ){ 1196 if(has_by_second && end_of_data && this_frequency ){
1172 increment_minute(impl,1); 1197 increment_minute(impl,1);
1173 } 1198 }
1174 1199
1175 return end_of_data; 1200 return end_of_data;
1176 1201
1177} 1202}
1178 1203
1179int next_minute(struct icalrecur_iterator_impl* impl) 1204static int next_minute(icalrecur_iterator* impl)
1180{ 1205{
1181 1206
1182 short has_by_data = (impl->by_ptrs[BY_MINUTE][0]!=ICAL_RECURRENCE_ARRAY_MAX); 1207 int has_by_minute = (impl->by_ptrs[BY_MINUTE][0]!=ICAL_RECURRENCE_ARRAY_MAX);
1183 short this_frequency = (impl->rule.freq == ICAL_MINUTELY_RECURRENCE); 1208 int this_frequency = (impl->rule.freq == ICAL_MINUTELY_RECURRENCE);
1184 1209
1185 short end_of_data = 0; 1210 int end_of_data = 0;
1186 1211
1187 assert(has_by_data || this_frequency); 1212 assert(has_by_minute || this_frequency);
1188 1213
1189 1214
1190 if (next_second(impl) == 0){ 1215 if (next_second(impl) == 0){
1191 return 0; 1216 return 0;
1192 } 1217 }
1193 1218
1194 if( has_by_data ){ 1219 if( has_by_minute ){
1195 /* Ignore the frequency and use the byrule data */ 1220 /* Ignore the frequency and use the byrule data */
1196 1221
1197 impl->by_indices[BY_MINUTE]++; 1222 impl->by_indices[BY_MINUTE]++;
1198 1223
1199 if (impl->by_ptrs[BY_MINUTE][impl->by_indices[BY_MINUTE]] 1224 if (impl->by_ptrs[BY_MINUTE][impl->by_indices[BY_MINUTE]]
1200 ==ICAL_RECURRENCE_ARRAY_MAX){ 1225 ==ICAL_RECURRENCE_ARRAY_MAX){
1201 1226
1202 impl->by_indices[BY_MINUTE] = 0; 1227 impl->by_indices[BY_MINUTE] = 0;
1203 1228
1204 end_of_data = 1; 1229 end_of_data = 1;
1205 } 1230 }
1206 1231
1207 impl->last.minute = 1232 impl->last.minute =
1208 impl->by_ptrs[BY_MINUTE][impl->by_indices[BY_MINUTE]]; 1233 impl->by_ptrs[BY_MINUTE][impl->by_indices[BY_MINUTE]];
1209 1234
1210 } else if( !has_by_data && this_frequency ){ 1235 } else if( !has_by_minute && this_frequency ){
1211 /* Compute the next value from the last time and the frequency interval*/ 1236 /* Compute the next value from the last time and the frequency interval*/
1212 increment_minute(impl,impl->rule.interval); 1237 increment_minute(impl,impl->rule.interval);
1213 } 1238 }
1214 1239
1215/* If we have gone through all of the minutes on the BY list, then we 1240/* If we have gone through all of the minutes on the BY list, then we
1216 need to move to the next hour */ 1241 need to move to the next hour */
1217 1242
1218 if(has_by_data && end_of_data && this_frequency ){ 1243 if(has_by_minute && end_of_data && this_frequency ){
1219 increment_hour(impl,1); 1244 increment_hour(impl,1);
1220 } 1245 }
1221 1246
1222 return end_of_data; 1247 return end_of_data;
1223} 1248}
1224 1249
1225int next_hour(struct icalrecur_iterator_impl* impl) 1250static int next_hour(icalrecur_iterator* impl)
1226{ 1251{
1227 1252
1228 short has_by_data = (impl->by_ptrs[BY_HOUR][0]!=ICAL_RECURRENCE_ARRAY_MAX); 1253 int has_by_hour = (impl->by_ptrs[BY_HOUR][0]!=ICAL_RECURRENCE_ARRAY_MAX);
1229 short this_frequency = (impl->rule.freq == ICAL_HOURLY_RECURRENCE); 1254 int this_frequency = (impl->rule.freq == ICAL_HOURLY_RECURRENCE);
1230 1255
1231 short end_of_data = 0; 1256 int end_of_data = 0;
1232 1257
1233 assert(has_by_data || this_frequency); 1258 assert(has_by_hour || this_frequency);
1234 1259
1235 if (next_minute(impl) == 0){ 1260 if (next_minute(impl) == 0){
1236 return 0; 1261 return 0;
1237 } 1262 }
1238 1263
1239 if( has_by_data ){ 1264 if( has_by_hour ){
1240 /* Ignore the frequency and use the byrule data */ 1265 /* Ignore the frequency and use the byrule data */
1241 1266
1242 impl->by_indices[BY_HOUR]++; 1267 impl->by_indices[BY_HOUR]++;
1243 1268
1244 if (impl->by_ptrs[BY_HOUR][impl->by_indices[BY_HOUR]] 1269 if (impl->by_ptrs[BY_HOUR][impl->by_indices[BY_HOUR]]
1245 ==ICAL_RECURRENCE_ARRAY_MAX){ 1270 ==ICAL_RECURRENCE_ARRAY_MAX){
1246 impl->by_indices[BY_HOUR] = 0; 1271 impl->by_indices[BY_HOUR] = 0;
1247 1272
1248 end_of_data = 1; 1273 end_of_data = 1;
1249 } 1274 }
1250 1275
1251 impl->last.hour = 1276 impl->last.hour =
1252 impl->by_ptrs[BY_HOUR][impl->by_indices[BY_HOUR]]; 1277 impl->by_ptrs[BY_HOUR][impl->by_indices[BY_HOUR]];
1253 1278
1254 } else if( !has_by_data && this_frequency ){ 1279 } else if( !has_by_hour && this_frequency ){
1255 /* Compute the next value from the last time and the frequency interval*/ 1280 /* Compute the next value from the last time and the frequency interval*/
1256 increment_hour(impl,impl->rule.interval); 1281 increment_hour(impl,impl->rule.interval);
1257 1282
1258 } 1283 }
1259 1284
1260 /* If we have gone through all of the hours on the BY list, then we 1285 /* If we have gone through all of the hours on the BY list, then we
1261 need to move to the next day */ 1286 need to move to the next day */
1262 1287
1263 if(has_by_data && end_of_data && this_frequency ){ 1288 if(has_by_hour && end_of_data && this_frequency ){
1264 increment_monthday(impl,1); 1289 increment_monthday(impl,1);
1265 } 1290 }
1266 1291
1267 return end_of_data; 1292 return end_of_data;
1268 1293
1269} 1294}
1270 1295
1271int next_day(struct icalrecur_iterator_impl* impl) 1296static int next_day(icalrecur_iterator* impl)
1272{ 1297{
1273 1298
1274 short has_by_data = (impl->by_ptrs[BY_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX); 1299 int has_by_day = (impl->by_ptrs[BY_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX);
1275 short this_frequency = (impl->rule.freq == ICAL_DAILY_RECURRENCE); 1300 int this_frequency = (impl->rule.freq == ICAL_DAILY_RECURRENCE);
1276 1301
1277 assert(has_by_data || this_frequency); 1302 assert(has_by_day || this_frequency);
1278 1303
1279 if (next_hour(impl) == 0){ 1304 if (next_hour(impl) == 0){
1280 return 0; 1305 return 0;
1281 } 1306 }
1282 1307
1283 /* Always increment through the interval, since this routine is not 1308 /* Always increment through the interval, since this routine is not
1284 called by any other next_* routine, and the days that are 1309 called by any other next_* routine, and the days that are
1285 excluded will be taken care of by restriction filtering */ 1310 excluded will be taken care of by restriction filtering */
1286 1311
1287 if(this_frequency){ 1312 if(this_frequency){
1288 increment_monthday(impl,impl->rule.interval); 1313 increment_monthday(impl,impl->rule.interval);
1289 } else { 1314 } else {
1290 increment_monthday(impl,1); 1315 increment_monthday(impl,1);
1291 } 1316 }
1292 1317
1293 1318
1294 return 0; 1319 return 0;
1295 1320
1296} 1321}
1297 1322
1298 1323
1299int next_yearday(struct icalrecur_iterator_impl* impl) 1324static int next_yearday(icalrecur_iterator* impl)
1300{ 1325{
1301 1326
1302 short has_by_data = (impl->by_ptrs[BY_YEAR_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX); 1327 int has_by_yearday = (impl->by_ptrs[BY_YEAR_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX);
1303 1328
1304 short end_of_data = 0; 1329 int end_of_data = 0;
1305 1330
1306 assert(has_by_data ); 1331 assert(has_by_yearday );
1307 1332
1308 if (next_hour(impl) == 0){ 1333 if (next_hour(impl) == 0){
1309 return 0; 1334 return 0;
1310 } 1335 }
1311 1336
1312 impl->by_indices[BY_YEAR_DAY]++; 1337 impl->by_indices[BY_YEAR_DAY]++;
1313 1338
1314 if (impl->by_ptrs[BY_YEAR_DAY][impl->by_indices[BY_YEAR_DAY]] 1339 if (impl->by_ptrs[BY_YEAR_DAY][impl->by_indices[BY_YEAR_DAY]]
1315 ==ICAL_RECURRENCE_ARRAY_MAX){ 1340 ==ICAL_RECURRENCE_ARRAY_MAX){
1316 impl->by_indices[BY_YEAR_DAY] = 0; 1341 impl->by_indices[BY_YEAR_DAY] = 0;
1317 1342
1318 end_of_data = 1; 1343 end_of_data = 1;
1319 } 1344 }
1320 1345
1321 impl->last.day = 1346 impl->last.day =
1322 impl->by_ptrs[BY_YEAR_DAY][impl->by_indices[BY_YEAR_DAY]]; 1347 impl->by_ptrs[BY_YEAR_DAY][impl->by_indices[BY_YEAR_DAY]];
1323 1348
1324 if(has_by_data && end_of_data){ 1349 if(has_by_yearday && end_of_data){
1325 increment_year(impl,1); 1350 increment_year(impl,1);
1326 } 1351 }
1327 1352
1328 return end_of_data; 1353 return end_of_data;
1329 1354
1330} 1355}
1331 1356
1332/* This routine is only called by next_week. It is certain that BY_DAY
1333has data */
1334
1335int next_weekday_by_week(struct icalrecur_iterator_impl* impl)
1336{
1337
1338 short end_of_data = 0;
1339 short start_of_week, dow;
1340 struct icaltimetype next;
1341
1342 if (next_hour(impl) == 0){
1343 return 0;
1344 }
1345
1346 assert( impl->by_ptrs[BY_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX);
1347
1348 while(1) {
1349
1350 impl->by_indices[BY_DAY]++; /* Look at next elem in BYDAY array */
1351
1352 /* Are we at the end of the BYDAY array? */
1353 if (impl->by_ptrs[BY_DAY][impl->by_indices[BY_DAY]]
1354 ==ICAL_RECURRENCE_ARRAY_MAX){
1355
1356 impl->by_indices[BY_DAY] = 0; /* Reset to 0 */
1357 end_of_data = 1; /* Signal that we're at the end */
1358 }
1359
1360 /* Add the day of week offset to to the start of this week, and use
1361 that to get the next day */
1362 dow = impl->by_ptrs[BY_DAY][impl->by_indices[BY_DAY]];
1363 start_of_week = icaltime_start_doy_of_week(impl->last);
1364 1357
1365 dow--; /*Sun is 1, not 0 */ 1358/* Returns the day of the month for the current month of t that is the
1359 pos'th instance of the day-of-week dow */
1366 1360
1367 if(dow+start_of_week <1 && !end_of_data){ 1361static int nth_weekday(int dow, int pos, struct icaltimetype t){
1368 /* The selected date is in the previous year. */
1369 continue;
1370 }
1371
1372 next = icaltime_from_day_of_year(start_of_week + dow,impl->last.year);
1373 1362
1374 impl->last.day = next.day; 1363 int days_in_month = icaltime_days_in_month(t.month, t.year);
1375 impl->last.month = next.month; 1364 int end_dow, start_dow;
1376 impl->last.year = next.year; 1365 int wd;
1377
1378 return end_of_data;
1379 }
1380
1381}
1382
1383int nth_weekday(short dow, short pos, struct icaltimetype t){
1384
1385 short days_in_month = icaltime_days_in_month(t.month,t.year);
1386 short end_dow, start_dow;
1387 short wd;
1388 1366
1389 if(pos >= 0){ 1367 if(pos >= 0){
1390 t.day = 1; 1368 t.day = 1;
1391 start_dow = icaltime_day_of_week(t); 1369 start_dow = icaltime_day_of_week(t);
1392 1370
1393 if (pos != 0) { 1371 if (pos != 0) {
1394 pos--; 1372 pos--;
1395 } 1373 }
1396 1374
1397 /* find month day of first occurrence of dow -- such as the 1375 /* find month day of first occurrence of dow -- such as the
1398 month day of the first monday */ 1376 month day of the first monday */
1399 1377
1400 wd = dow-start_dow+1; 1378 wd = dow-start_dow+1;
1401 1379
1402 if (wd <= 0){ 1380 if (wd <= 0){
1403 wd = wd + 7; 1381 wd = wd + 7;
1404 } 1382 }
1405 1383
1406 wd = wd + pos * 7; 1384 wd = wd + pos * 7;
1407 1385
1408 } else { 1386 } else {
1409 t.day = days_in_month; 1387 t.day = days_in_month;
1410 end_dow = icaltime_day_of_week(t); 1388 end_dow = icaltime_day_of_week(t);
1411 1389
1412 pos++; 1390 pos++;
1413 1391
1414 /* find month day of last occurrence of dow -- such as the 1392 /* find month day of last occurrence of dow -- such as the
1415 month day of the last monday */ 1393 month day of the last monday */
1416 1394
1417 wd = (end_dow - dow); 1395 wd = (end_dow - dow);
1418 1396
1419 if (wd < 0){ 1397 if (wd < 0){
1420 wd = wd+ 7; 1398 wd = wd+ 7;
1421 } 1399 }
1422 1400
1423 wd = days_in_month - wd; 1401 wd = days_in_month - wd;
1424 1402
1425 wd = wd + pos * 7; 1403 wd = wd + pos * 7;
1426 } 1404 }
1427 1405
1428 return wd; 1406 return wd;
1429} 1407}
1430 1408
1409static int is_day_in_byday(icalrecur_iterator* impl,struct icaltimetype tt){
1410
1411 int idx;
1412
1413 for(idx = 0; BYDAYPTR[idx] != ICAL_RECURRENCE_ARRAY_MAX; idx++){
1414 int dow = icalrecurrencetype_day_day_of_week(BYDAYPTR[idx]);
1415 int pos = icalrecurrencetype_day_position(BYDAYPTR[idx]);
1416 int this_dow = icaltime_day_of_week(tt);
1417
1418 if( (pos == 0 && dow == this_dow ) || /* Just a dow, like "TU" or "FR" */
1419 (nth_weekday(dow,pos,tt) == tt.day)){ /*pos+wod: "3FR" or -1TU" */
1420 return 1;
1421 }
1422 }
1423
1424 return 0;
1425}
1431 1426
1432int next_month(struct icalrecur_iterator_impl* impl) 1427static int next_month(icalrecur_iterator* impl)
1433{ 1428{
1434 int data_valid = 1; 1429 int data_valid = 1;
1435 1430
1436 short this_frequency = (impl->rule.freq == ICAL_MONTHLY_RECURRENCE); 1431 int this_frequency = (impl->rule.freq == ICAL_MONTHLY_RECURRENCE);
1437 1432
1438 assert( has_by_data(impl,BY_MONTH) || this_frequency); 1433 assert( has_by_data(impl,BY_MONTH) || this_frequency);
1439 1434
1440 /* Iterate through the occurrences within a day. If we don't get to 1435 /* Iterate through the occurrences within a day. If we don't get to
1441 the end of the intra-day data, don't bother going to the next 1436 the end of the intra-day data, don't bother going to the next
1442 month */ 1437 month */
1443 1438
1444 if (next_hour(impl) == 0){ 1439 if (next_hour(impl) == 0){
1445 return data_valid; /* Signal that the data is valid */ 1440 return data_valid; /* Signal that the data is valid */
1446 } 1441 }
1447 1442
1448
1449 /* Now iterate through the occurrences within a month -- by days, 1443 /* Now iterate through the occurrences within a month -- by days,
1450 weeks or weekdays. */ 1444 weeks or weekdays. */
1451 1445
1446 /*
1447 * Case 1:
1448 * Rules Like: FREQ=MONTHLY;INTERVAL=1;BYDAY=FR;BYMONTHDAY=13
1449 */
1450
1452 if(has_by_data(impl,BY_DAY) && has_by_data(impl,BY_MONTH_DAY)){ 1451 if(has_by_data(impl,BY_DAY) && has_by_data(impl,BY_MONTH_DAY)){
1453 /* Cases like: FREQ=MONTHLY;INTERVAL=1;BYDAY=FR;BYMONTHDAY=13 */ 1452 int day, idx,j;
1454 short day, idx,j; 1453 int days_in_month = icaltime_days_in_month(impl->last.month,
1455 short days_in_month = icaltime_days_in_month(impl->last.month,
1456 impl->last.year); 1454 impl->last.year);
1457 /* Iterate through the remaining days in the month and check if 1455 /* Iterate through the remaining days in the month and check if
1458 each day is listed in the BY_DAY array and in the BY_MONTHDAY 1456 each day is listed in the BY_DAY array and in the BY_MONTHDAY
1459 array. This seems very inneficient, but I think it is the 1457 array. This seems very inneficient, but I think it is the
1460 simplest way to account for both BYDAY=1FR (First friday in 1458 simplest way to account for both BYDAY=1FR (First friday in
1461 month) and BYDAY=FR ( every friday in month ) */ 1459 month) and BYDAY=FR ( every friday in month ) */
1462 1460
1463 for(day = impl->last.day+1; day <= days_in_month; day++){ 1461 for(day = impl->last.day+1; day <= days_in_month; day++){
1464 for(idx = 0; BYDAYPTR[idx] != ICAL_RECURRENCE_ARRAY_MAX; idx++){ 1462 for(idx = 0; BYDAYPTR[idx] != ICAL_RECURRENCE_ARRAY_MAX; idx++){
1465 for(j = 0; BYMDPTR[j]!=ICAL_RECURRENCE_ARRAY_MAX; j++){ 1463 for(j = 0; BYMDPTR[j]!=ICAL_RECURRENCE_ARRAY_MAX; j++){
1466 short dow = 1464 int dow =
1467 icalrecurrencetype_day_day_of_week(BYDAYPTR[idx]); 1465 icalrecurrencetype_day_day_of_week(BYDAYPTR[idx]);
1468 short pos = icalrecurrencetype_day_position(BYDAYPTR[idx]); 1466 int pos = icalrecurrencetype_day_position(BYDAYPTR[idx]);
1469 short mday = BYMDPTR[j]; 1467 int mday = BYMDPTR[j];
1470 short this_dow; 1468 int this_dow;
1471 1469
1472 impl->last.day = day; 1470 impl->last.day = day;
1473 this_dow = icaltime_day_of_week(impl->last); 1471 this_dow = icaltime_day_of_week(impl->last);
1474 1472
1475 if( (pos == 0 && dow == this_dow && mday == day) || 1473 if( (pos == 0 && dow == this_dow && mday == day) ||
1476 (nth_weekday(dow,pos,impl->last) == day && mday==day)){ 1474 (nth_weekday(dow,pos,impl->last) == day && mday==day)){
1477 goto MDEND; 1475 goto MDEND;
1478 } 1476 }
1479 } 1477 }
1480 } 1478 }
1481 } 1479 }
1482 1480
1483 MDEND: 1481 MDEND:
1484 1482
1485 if ( day > days_in_month){ 1483 if ( day > days_in_month){
1486 impl->last.day = 1; 1484 impl->last.day = 1;
1487 increment_month(impl); 1485 increment_month(impl);
1488 data_valid = 0; /* signal that impl->last is invalid */ 1486 data_valid = 0; /* signal that impl->last is invalid */
1489 } 1487 }
1490 1488
1491 1489
1490 /*
1491 * Case 2:
1492 * Rules Like: FREQ=MONTHLY;INTERVAL=1;BYDAY=FR
1493 */
1494
1492 } else if(has_by_data(impl,BY_DAY)){ 1495 } else if(has_by_data(impl,BY_DAY)){
1493 /* Cases like: FREQ=MONTHLY;INTERVAL=1;BYDAY=FR */
1494 /* For this case, the weekdays are relative to the 1496 /* For this case, the weekdays are relative to the
1495 month. BYDAY=FR -> First Friday in month, etc. */ 1497 month. BYDAY=FR -> First Friday in month, etc. */
1496 1498
1497 short day, idx; 1499 /* This code iterates through the remaining days in the month
1498 short days_in_month = icaltime_days_in_month(impl->last.month, 1500 and checks if each day is listed in the BY_DAY array. This
1499 impl->last.year); 1501 seems very inneficient, but I think it is the simplest way to
1502 account for both BYDAY=1FR (First friday in month) and
1503 BYDAY=FR ( every friday in month ) */
1500 1504
1505 int day;
1506 int days_in_month = icaltime_days_in_month(impl->last.month,
1507 impl->last.year);
1501 assert( BYDAYPTR[0]!=ICAL_RECURRENCE_ARRAY_MAX); 1508 assert( BYDAYPTR[0]!=ICAL_RECURRENCE_ARRAY_MAX);
1502 1509
1503 /* Iterate through the remaining days in the month and check if
1504 each day is listed in the BY_DAY array. This seems very
1505 inneficient, but I think it is the simplest way to account
1506 for both BYDAY=1FR (First friday in month) and BYDAY=FR (
1507 every friday in month ) */
1508
1509 for(day = impl->last.day+1; day <= days_in_month; day++){ 1510 for(day = impl->last.day+1; day <= days_in_month; day++){
1510 for(idx = 0; BYDAYPTR[idx] != ICAL_RECURRENCE_ARRAY_MAX; idx++){
1511 short dow = icalrecurrencetype_day_day_of_week(BYDAYPTR[idx]);
1512 short pos = icalrecurrencetype_day_position(BYDAYPTR[idx]);
1513 short this_dow;
1514
1515 impl->last.day = day; 1511 impl->last.day = day;
1516 this_dow = icaltime_day_of_week(impl->last); 1512 if(is_day_in_byday(impl,impl->last)){
1517 1513 data_valid = 1;
1518 if( (pos == 0 && dow == this_dow ) || 1514 break;
1519 (nth_weekday(dow,pos,impl->last) == day)){
1520 goto DEND;
1521 }
1522 } 1515 }
1523 } 1516 }
1524 1517
1525 DEND:
1526
1527 if ( day > days_in_month){ 1518 if ( day > days_in_month){
1528 impl->last.day = 1; 1519 impl->last.day = 1;
1529 increment_month(impl); 1520 increment_month(impl);
1521
1522 /* Did moving to the next month put us on a valid date? if
1523 so, note that the new data is valid, if, not, mark it
1524 invalid */
1525
1526 if(is_day_in_byday(impl,impl->last)){
1527 data_valid = 1;
1528 } else {
1530 data_valid = 0; /* signal that impl->last is invalid */ 1529 data_valid = 0; /* signal that impl->last is invalid */
1531 } 1530 }
1531 }
1532
1533 /*
1534 * Case 3
1535 * Rules Like: FREQ=MONTHLY;COUNT=10;BYMONTHDAY=-3
1536 */
1532 1537
1533 } else if (has_by_data(impl,BY_MONTH_DAY)) { 1538 } else if (has_by_data(impl,BY_MONTH_DAY)) {
1534 /* Cases like: FREQ=MONTHLY;COUNT=10;BYMONTHDAY=-3 */ 1539 int day;
1535 short day;
1536 1540
1537 assert( BYMDPTR[0]!=ICAL_RECURRENCE_ARRAY_MAX); 1541 assert( BYMDPTR[0]!=ICAL_RECURRENCE_ARRAY_MAX);
1538 1542
1539 BYMDIDX++; 1543 BYMDIDX++;
1540 1544
1541 /* Are we at the end of the BYDAY array? */ 1545 /* Are we at the end of the BYDAY array? */
1542 if (BYMDPTR[BYMDIDX] ==ICAL_RECURRENCE_ARRAY_MAX){ 1546 if (BYMDPTR[BYMDIDX] ==ICAL_RECURRENCE_ARRAY_MAX){
1543 1547
1544 BYMDIDX = 0; /* Reset to 0 */ 1548 BYMDIDX = 0; /* Reset to 0 */
1545 increment_month(impl); 1549 increment_month(impl);
1546 } 1550 }
1547 1551
1548 day = BYMDPTR[BYMDIDX]; 1552 day = BYMDPTR[BYMDIDX];
1549 1553
1550 if (day < 0) { 1554 if (day < 0) {
1551 day = icaltime_days_in_month(impl->last.month,impl->last.year)+ 1555 day = icaltime_days_in_month(impl->last.month, impl->last.year) + day + 1;
1552 day + 1;
1553 } 1556 }
1554 1557
1555 impl->last.day = day; 1558 impl->last.day = day;
1556 1559
1557 } else { 1560 } else {
1558 increment_month(impl); 1561 increment_month(impl);
1559 } 1562 }
1560 1563
1561 return data_valid; /* Signal that the data is valid */ 1564 return data_valid;
1565
1566}
1567
1568static int next_weekday_by_week(icalrecur_iterator* impl)
1569{
1570
1571 int end_of_data = 0;
1572 int start_of_week, dow;
1573 struct icaltimetype next;
1574
1575 if (next_hour(impl) == 0){
1576 return 0;
1577 }
1578
1579 if(!has_by_data(impl,BY_DAY)){
1580 return 1;
1581 }
1582
1583 /* If we get here, we need to step to tne next day */
1584
1585 for (;;) {
1586 struct icaltimetype tt = icaltime_null_time();
1587 BYDAYIDX++; /* Look at next elem in BYDAY array */
1588
1589 /* Are we at the end of the BYDAY array? */
1590 if (BYDAYPTR[BYDAYIDX]==ICAL_RECURRENCE_ARRAY_MAX){
1591 BYDAYIDX = 0; /* Reset to 0 */
1592 end_of_data = 1; /* Signal that we're at the end */
1593 }
1594
1595 /* Add the day of week offset to to the start of this week, and use
1596 that to get the next day */
1597 /* ignore position of dow ("4FR"), only use dow ("FR")*/
1598 dow = icalrecurrencetype_day_day_of_week(BYDAYPTR[BYDAYIDX]);
1599 tt.year = impl->last.year;
1600 tt.day = impl->last.day;
1601 tt.month = impl->last.month;
1562 1602
1603 start_of_week = icaltime_start_doy_of_week(tt);
1604
1605 dow--; /* Set Sunday to be 0 */
1606
1607 if(dow+start_of_week <1){
1608 /* The selected date is in the previous year. */
1609 if(!end_of_data){
1610 continue;
1563} 1611}
1612 }
1613
1614 next = icaltime_from_day_of_year(start_of_week + dow,impl->last.year);
1564 1615
1616 impl->last.day = next.day;
1617 impl->last.month = next.month;
1618 impl->last.year = next.year;
1619
1620 return end_of_data;
1621 }
1565 1622
1566int next_week(struct icalrecur_iterator_impl* impl) 1623}
1624
1625static int next_week(icalrecur_iterator* impl)
1567{ 1626{
1568 short has_by_data = (impl->by_ptrs[BY_WEEK_NO][0]!=ICAL_RECURRENCE_ARRAY_MAX); 1627 int end_of_data = 0;
1569 short this_frequency = (impl->rule.freq == ICAL_WEEKLY_RECURRENCE);
1570 short end_of_data = 0;
1571 1628
1572 /* Increment to the next week day */ 1629 /* Increment to the next week day, if there is data at a level less than a week */
1573 if (next_weekday_by_week(impl) == 0){ 1630 if (next_weekday_by_week(impl) == 0){
1574 return 0; /* Have not reached end of week yet */ 1631 return 0; /* Have not reached end of week yet */
1575 } 1632 }
1576 1633
1577 /* If we get here, we have incremented through the entire week, and 1634 /* If we get here, we have incremented through the entire week, and
1578 can increment to the next week */ 1635 can increment to the next week */
1579 1636
1580 1637 if( has_by_data(impl,BY_WEEK_NO)){
1581 if( has_by_data){ 1638 /*FREQ=WEEKLY;BYWEEK=20*/
1582 /* Use the Week Number byrule data */ 1639 /* Use the Week Number byrule data */
1583 int week_no; 1640 int week_no;
1584 struct icaltimetype t; 1641 struct icaltimetype t;
1585 1642
1586 impl->by_indices[BY_WEEK_NO]++; 1643 impl->by_indices[BY_WEEK_NO]++;
1587 1644
1588 if (impl->by_ptrs[BY_WEEK_NO][impl->by_indices[BY_WEEK_NO]] 1645 if (impl->by_ptrs[BY_WEEK_NO][impl->by_indices[BY_WEEK_NO]]
1589 ==ICAL_RECURRENCE_ARRAY_MAX){ 1646 ==ICAL_RECURRENCE_ARRAY_MAX){
1590 impl->by_indices[BY_WEEK_NO] = 0; 1647 impl->by_indices[BY_WEEK_NO] = 0;
1591 1648
1592 end_of_data = 1; 1649 end_of_data = 1;
1593 } 1650 }
1594 1651
1595 t = impl->last; 1652 t = impl->last;
1596 t.month=1; /* HACK, should be setting to the date of the first week of year*/ 1653 t.month=1; /* HACK, should be setting to the date of the first week of year*/
1597 t.day=1; 1654 t.day=1;
1598 1655
1599 week_no = impl->by_ptrs[BY_WEEK_NO][impl->by_indices[BY_WEEK_NO]]; 1656 week_no = impl->by_ptrs[BY_WEEK_NO][impl->by_indices[BY_WEEK_NO]];
1600 1657
1601 impl->last.day += week_no*7; 1658 impl->last.day += week_no*7;
1602 1659
1603 impl->last = icaltime_normalize(impl->last); 1660 impl->last = icaltime_normalize(impl->last);
1604 1661
1605 } else if( !has_by_data && this_frequency ){ 1662 } else {
1606 /* If there is no BY_WEEK_NO data, just jump forward 7 days. */ 1663 /* Jump to the next week */
1607 increment_monthday(impl,7*impl->rule.interval); 1664 increment_monthday(impl,7*impl->rule.interval);
1608 } 1665 }
1609 1666
1610 1667 if( has_by_data(impl,BY_WEEK_NO) && end_of_data){
1611 if(has_by_data && end_of_data && this_frequency ){
1612 increment_year(impl,1); 1668 increment_year(impl,1);
1613 } 1669 }
1614 1670
1615 return end_of_data; 1671 return end_of_data;
1616 1672
1617} 1673}
1618 1674
1619/* Expand the BYDAY rule part and return a pointer to a newly allocated list of days. */ 1675/** Expand the BYDAY rule part and return a pointer to a newly allocated list of days. */
1620pvl_list expand_by_day(struct icalrecur_iterator_impl* impl,short year) 1676static pvl_list expand_by_day(icalrecur_iterator* impl, int year)
1621{ 1677{
1622 /* Try to calculate each of the occurrences. */ 1678 /* Try to calculate each of the occurrences. */
1623 int i; 1679 int i;
1624 pvl_list days_list = pvl_newlist(); 1680 pvl_list days_list = pvl_newlist();
1625 1681
1626 short start_dow, end_dow, end_year_day, start_doy; 1682 int start_dow, end_dow, end_year_day;
1627 struct icaltimetype tmp = impl->last; 1683 struct icaltimetype tmp = impl->last;
1628 1684
1629 tmp.year= year; 1685 tmp.year= year;
1630 tmp.month = 1; 1686 tmp.month = 1;
1631 tmp.day = 1; 1687 tmp.day = 1;
1632 tmp.is_date = 1; 1688 tmp.is_date = 1;
1633 1689
1690 /* Find the day that 1st Jan falls on, 1 (Sun) to 7 (Sat). */
1634 start_dow = icaltime_day_of_week(tmp); 1691 start_dow = icaltime_day_of_week(tmp);
1635 start_doy = icaltime_start_doy_of_week(tmp);
1636 1692
1637 /* Get the last day of the year*/ 1693 /* Get the last day of the year*/
1638 tmp.year++; 1694 tmp.year= year;
1639 tmp = icaltime_normalize(tmp); 1695 tmp.month = 12;
1640 tmp.day--; 1696 tmp.day = 31;
1641 tmp = icaltime_normalize(tmp); 1697 tmp.is_date = 1;
1642 1698
1643 end_dow = icaltime_day_of_week(tmp); 1699 end_dow = icaltime_day_of_week(tmp);
1644 end_year_day = icaltime_day_of_year(tmp); 1700 end_year_day = icaltime_day_of_year(tmp);
1645 1701
1646 for(i = 0; BYDAYPTR[i] != ICAL_RECURRENCE_ARRAY_MAX; i++){ 1702 for(i = 0; BYDAYPTR[i] != ICAL_RECURRENCE_ARRAY_MAX; i++){
1647 short dow = 1703 /* This is 1 (Sun) to 7 (Sat). */
1704 int dow =
1648 icalrecurrencetype_day_day_of_week(BYDAYPTR[i]); 1705 icalrecurrencetype_day_day_of_week(BYDAYPTR[i]);
1649 short pos = icalrecurrencetype_day_position(BYDAYPTR[i]); 1706 int pos = icalrecurrencetype_day_position(BYDAYPTR[i]);
1650 1707
1651 if(pos == 0){ 1708 if(pos == 0){
1652 /* The day was specified without a position -- it is just 1709 /* The day was specified without a position -- it is just
1653 a bare day of the week ( BYDAY=SU) so add all of the 1710 a bare day of the week ( BYDAY=SU) so add all of the
1654 days of the year with this day-of-week*/ 1711 days of the year with this day-of-week*/
1655 int week; 1712 int doy, tmp_start_doy;
1656 for(week = 0; week < 52 ; week ++){
1657 short doy = start_doy + (week * 7) + dow-1;
1658 1713
1659 if(doy > end_year_day){ 1714 tmp_start_doy = ((dow + 7 - start_dow) % 7) + 1;
1660 break; 1715
1661 } else { 1716 for (doy = tmp_start_doy; doy <= end_year_day; doy += 7)
1662 pvl_push(days_list,(void*)(int)doy); 1717 pvl_push(days_list,(void*)(int)doy);
1663 } 1718
1664 }
1665 } else if ( pos > 0) { 1719 } else if ( pos > 0) {
1666 int first; 1720 int first;
1667 /* First occurrence of dow in year */ 1721 /* First occurrence of dow in year */
1668 if( dow >= start_dow) { 1722 if( dow >= start_dow) {
1669 first = dow - start_dow + 1; 1723 first = dow - start_dow + 1;
1670 } else { 1724 } else {
1671 first = dow - start_dow + 8; 1725 first = dow - start_dow + 8;
1672 } 1726 }
1673 1727
1674 /* THen just multiple the position times 7 to get the pos'th day in the year */ 1728 /* Then just multiple the position times 7 to get the pos'th day in the year */
1675 pvl_push(days_list,(void*)(first+ (pos-1) * 7)); 1729 pvl_push(days_list,(void*)(first+ (pos-1) * 7));
1676 1730
1677 } else { /* pos < 0 */ 1731 } else { /* pos < 0 */
1678 int last; 1732 int last;
1679 pos = -pos; 1733 pos = -pos;
1680 1734
1681 /* last occurrence of dow in year */ 1735 /* last occurrence of dow in year */
1682 if( dow <= end_dow) { 1736 if( dow <= end_dow) {
1683 last = end_year_day - end_dow + dow; 1737 last = end_year_day - end_dow + dow;
1684 } else { 1738 } else {
1685 last = end_year_day - end_dow + dow - 7; 1739 last = end_year_day - end_dow + dow - 7;
1686 } 1740 }
1687 1741
1688 pvl_push(days_list,(void*)(last - (pos-1) * 7)); 1742 pvl_push(days_list,(void*)(last - (pos-1) * 7));
1689 } 1743 }
1690 } 1744 }
1691 return days_list; 1745 return days_list;
1692} 1746}
1693 1747
1694 1748
1695/* For INTERVAL=YEARLY, set up the days[] array in the iterator to 1749/* For INTERVAL=YEARLY, set up the days[] array in the iterator to
1696 list all of the days of the current year that are specified in this 1750 list all of the days of the current year that are specified in this
1697 rule. */ 1751 rule. */
1698 1752
1699int expand_year_days(struct icalrecur_iterator_impl* impl,short year) 1753static int expand_year_days(icalrecur_iterator* impl, int year)
1700{ 1754{
1701 int j,k; 1755 int j,k;
1702 int days_index=0; 1756 int days_index=0;
1703 struct icaltimetype t; 1757 struct icaltimetype t;
1704 int flags; 1758 int flags;
1705 1759
1706 t = icaltime_null_time(); 1760 t = icaltime_null_date();
1707 1761
1708#define HBD(x) has_by_data(impl,x) 1762#define HBD(x) has_by_data(impl,x)
1709 1763
1710 t.is_date = 1; /* Needed to make day_of_year routines work property */
1711
1712 memset(&t,0,sizeof(t));
1713 memset(impl->days,ICAL_RECURRENCE_ARRAY_MAX_BYTE,sizeof(impl->days)); 1764 memset(impl->days,ICAL_RECURRENCE_ARRAY_MAX_BYTE,sizeof(impl->days));
1714 1765
1766 /* The flags and the following switch statement select which code
1767 to use to expand the yers days, based on which BY-rules are
1768 present. */
1769
1715 flags = (HBD(BY_DAY) ? 1<<BY_DAY : 0) + 1770 flags = (HBD(BY_DAY) ? 1<<BY_DAY : 0) +
1716 (HBD(BY_WEEK_NO) ? 1<<BY_WEEK_NO : 0) + 1771 (HBD(BY_WEEK_NO) ? 1<<BY_WEEK_NO : 0) +
1717 (HBD(BY_MONTH_DAY) ? 1<<BY_MONTH_DAY : 0) + 1772 (HBD(BY_MONTH_DAY) ? 1<<BY_MONTH_DAY : 0) +
1718 (HBD(BY_MONTH) ? 1<<BY_MONTH : 0) + 1773 (HBD(BY_MONTH) ? 1<<BY_MONTH : 0) +
1719 (HBD(BY_YEAR_DAY) ? 1<<BY_YEAR_DAY : 0); 1774 (HBD(BY_YEAR_DAY) ? 1<<BY_YEAR_DAY : 0);
1720 1775
1721 1776
1722 switch(flags) { 1777 switch(flags) {
1723 1778
1724 case 0: { 1779 case 0: {
1725 /* FREQ=YEARLY; */ 1780 /* FREQ=YEARLY; */
1781 t = impl->dtstart;
1782 t.year = impl->last.year;
1783
1784 impl->days[days_index++] = (short)icaltime_day_of_year(t);
1726 1785
1727 break; 1786 break;
1728 } 1787 }
1729 case 1<<BY_MONTH: { 1788 case 1<<BY_MONTH: {
1730 /* FREQ=YEARLY; BYMONTH=3,11*/ 1789 /* FREQ=YEARLY; BYMONTH=3,11*/
1731 1790
1732 for(j=0;impl->by_ptrs[BY_MONTH][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){ 1791 for(j=0;impl->by_ptrs[BY_MONTH][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){
1733 struct icaltimetype t; 1792 int month = impl->by_ptrs[BY_MONTH][j];
1734 short month = impl->by_ptrs[BY_MONTH][j]; 1793 int doy;
1735 short doy;
1736 1794
1737 t = impl->dtstart; 1795 t = impl->dtstart;
1738 t.year = year; 1796 t.year = year;
1739 t.month = month; 1797 t.month = month;
1740 t.is_date = 1; 1798 t.is_date = 1;
1741 1799
1742 doy = icaltime_day_of_year(t); 1800 doy = icaltime_day_of_year(t);
1743 1801
1744 impl->days[days_index++] = doy; 1802 impl->days[days_index++] = (short)doy;
1745 1803
1746 } 1804 }
1747 break; 1805 break;
1748 } 1806 }
1749 1807
1750 case 1<<BY_MONTH_DAY: { 1808 case 1<<BY_MONTH_DAY: {
1751 /* FREQ=YEARLY; BYMONTHDAY=1,15*/ 1809 /* FREQ=YEARLY; BYMONTHDAY=1,15*/
1752 for(k=0;impl->by_ptrs[BY_MONTH_DAY][k]!=ICAL_RECURRENCE_ARRAY_MAX;k++) 1810 for(k=0;impl->by_ptrs[BY_MONTH_DAY][k]!=ICAL_RECURRENCE_ARRAY_MAX;k++)
1753 { 1811 {
1754 short month_day = impl->by_ptrs[BY_MONTH_DAY][k]; 1812 int month_day = impl->by_ptrs[BY_MONTH_DAY][k];
1755 short doy; 1813 int doy;
1756 1814
1757 t = impl->dtstart; 1815 t = impl->dtstart;
1758 t.day = month_day; 1816 t.day = month_day;
1759 t.year = year; 1817 t.year = year;
1760 t.is_date = 1; 1818 t.is_date = 1;
1761 1819
1762 doy = icaltime_day_of_year(t); 1820 doy = icaltime_day_of_year(t);
1763 1821
1764 impl->days[days_index++] = doy; 1822 impl->days[days_index++] = (short)doy;
1765 1823
1766 } 1824 }
1767 break; 1825 break;
1768 } 1826 }
1769 1827
1770 case (1<<BY_MONTH_DAY) + (1<<BY_MONTH): { 1828 case (1<<BY_MONTH_DAY) + (1<<BY_MONTH): {
1771 /* FREQ=YEARLY; BYMONTHDAY=1,15; BYMONTH=10 */ 1829 /* FREQ=YEARLY; BYMONTHDAY=1,15; BYMONTH=10 */
1772 1830
1773 for(j=0;impl->by_ptrs[BY_MONTH][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){ 1831 for(j=0;impl->by_ptrs[BY_MONTH][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){
1774 for(k=0;impl->by_ptrs[BY_MONTH_DAY][k]!=ICAL_RECURRENCE_ARRAY_MAX;k++) 1832 for(k=0;impl->by_ptrs[BY_MONTH_DAY][k]!=ICAL_RECURRENCE_ARRAY_MAX;k++)
1775 { 1833 {
1776 short month = impl->by_ptrs[BY_MONTH][j]; 1834 int month = impl->by_ptrs[BY_MONTH][j];
1777 short month_day = impl->by_ptrs[BY_MONTH_DAY][k]; 1835 int month_day = impl->by_ptrs[BY_MONTH_DAY][k];
1778 short doy; 1836 int doy;
1779 1837
1780 t.day = month_day; 1838 t.day = month_day;
1781 t.month = month; 1839 t.month = month;
1782 t.year = year; 1840 t.year = year;
1783 t.is_date = 1; 1841 t.is_date = 1;
1784 1842
1785 doy = icaltime_day_of_year(t); 1843 doy = icaltime_day_of_year(t);
1786 1844
1787 impl->days[days_index++] = doy; 1845 impl->days[days_index++] = (short)doy;
1788 1846
1789 } 1847 }
1790 } 1848 }
1791 1849
1792 break; 1850 break;
1793 } 1851 }
1794 1852
1795 case 1<<BY_WEEK_NO: { 1853 case 1<<BY_WEEK_NO: {
1796 /* FREQ=YEARLY; BYWEEKNO=20,50 */ 1854 /* FREQ=YEARLY; BYWEEKNO=20,50 */
1797 1855
1798 struct icaltimetype t; 1856 int dow;
1799 short dow;
1800 1857
1801 t.day = impl->dtstart.day; 1858 t.day = impl->dtstart.day;
1802 t.month = impl->dtstart.month; 1859 t.month = impl->dtstart.month;
1803 t.year = year; 1860 t.year = year;
1804 t.is_date = 1; 1861 t.is_date = 1;
1805 1862
1806 dow = icaltime_day_of_week(t); 1863 dow = icaltime_day_of_week(t);
1807 /* HACK Not finished */ 1864 /* HACK Not finished */
1808 1865
1809 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); 1866 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
1810 1867
1811 break; 1868 break;
1812 } 1869 }
1813 1870
1814 case (1<<BY_WEEK_NO) + (1<<BY_MONTH_DAY): { 1871 case (1<<BY_WEEK_NO) + (1<<BY_MONTH_DAY): {
1815 /*FREQ=YEARLY; WEEKNO=20,50; BYMONTH= 6,11 */ 1872 /*FREQ=YEARLY; WEEKNO=20,50; BYMONTH= 6,11 */
1816 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); 1873 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
1817 break; 1874 break;
1818 } 1875 }
1819 1876
1820 case 1<<BY_DAY: { 1877 case 1<<BY_DAY: {
1821 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR*/ 1878 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR*/
1822 int days_index = 0;
1823 pvl_elem i; 1879 pvl_elem i;
1824 pvl_list days = expand_by_day(impl,year); 1880 pvl_list days = expand_by_day(impl,year);
1825 1881
1826 1882
1827 for(i=pvl_head(days);i!=0;i=pvl_next(i)){ 1883 for(i=pvl_head(days);i!=0;i=pvl_next(i)){
1828 short day = (short)(int)pvl_data(i); 1884 short day = (short)(*((int*)pvl_data(i)));
1829 impl->days[days_index++] = day; 1885 impl->days[days_index++] = day;
1830 } 1886 }
1831 1887
1832 pvl_free(days); 1888 pvl_free(days);
1833 1889
1834 break; 1890 break;
1835 } 1891 }
1836 1892
1837 case (1<<BY_DAY)+(1<<BY_MONTH): { 1893 case (1<<BY_DAY)+(1<<BY_MONTH): {
1838 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; BYMONTH = 12*/ 1894 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; BYMONTH = 12*/
1839 1895
1840 int days_index = 0;
1841 pvl_elem itr;
1842 pvl_list days = expand_by_day(impl,year);
1843 1896
1844 for(itr=pvl_head(days);itr!=0;itr=pvl_next(itr)){ 1897 for(j=0;impl->by_ptrs[BY_MONTH][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){
1845 short doy = (short)(int)pvl_data(itr); 1898 int month = impl->by_ptrs[BY_MONTH][j];
1846 struct icaltimetype tt; 1899 int days_in_month = icaltime_days_in_month(month,year);
1847 short j; 1900 int first_dow, last_dow, doy_offset;
1848 1901
1849 tt = icaltime_from_day_of_year(doy,year); 1902 t.year = year;
1903 t.month = month;
1904 t.day = 1;
1905 t.is_date = 1;
1850 1906
1851 for(j=0; 1907 first_dow = icaltime_day_of_week(t);
1852 impl->by_ptrs[BY_MONTH][j]!=ICAL_RECURRENCE_ARRAY_MAX;
1853 j++){
1854 short month = impl->by_ptrs[BY_MONTH][j];
1855 1908
1856 if(tt.month == month){ 1909 /* This holds the day offset used to calculate the day of the year
1857 impl->days[days_index++] = doy; 1910 from the month day. Just add the month day to this. */
1858 } 1911 doy_offset = icaltime_day_of_year(t) - 1;
1859 }
1860 1912
1861 } 1913 t.day = days_in_month;
1914 last_dow = icaltime_day_of_week(t);
1862 1915
1863 pvl_free(days); 1916 for(k=0;impl->by_ptrs[BY_DAY][k]!=ICAL_RECURRENCE_ARRAY_MAX;k++){
1917 short day_coded = impl->by_ptrs[BY_DAY][k];
1918 enum icalrecurrencetype_weekday dow =
1919 icalrecurrencetype_day_day_of_week(day_coded);
1920 int pos = icalrecurrencetype_day_position(day_coded);
1921 int first_matching_day, last_matching_day, day, month_day;
1922
1923 /* Calculate the first day in the month with the given weekday,
1924 and the last day. */
1925 first_matching_day = ((dow + 7 - first_dow) % 7) + 1;
1926 last_matching_day = days_in_month - ((last_dow + 7 - dow) % 7);
1927
1928 if (pos == 0) {
1929 /* Add all of instances of the weekday within the month. */
1930 for (day = first_matching_day; day <= days_in_month; day += 7)
1931 impl->days[days_index++] = (short)(doy_offset + day);
1932
1933 } else if (pos > 0) {
1934 /* Add the nth instance of the weekday within the month. */
1935 month_day = first_matching_day + (pos - 1) * 7;
1936
1937 if (month_day <= days_in_month)
1938 impl->days[days_index++] = (short)(doy_offset + month_day);
1864 1939
1940 } else {
1941 /* Add the -nth instance of the weekday within the month.*/
1942 month_day = last_matching_day + (pos + 1) * 7;
1943
1944 if (month_day > 0)
1945 impl->days[days_index++] = (short)(doy_offset + month_day);
1946 }
1947 }
1948 }
1865 break; 1949 break;
1866 } 1950 }
1867 1951
1868 case (1<<BY_DAY) + (1<<BY_MONTH_DAY) : { 1952 case (1<<BY_DAY) + (1<<BY_MONTH_DAY) : {
1869 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; BYMONTHDAY=1,15*/ 1953 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; BYMONTHDAY=1,15*/
1870 1954
1871 int days_index = 0;
1872 pvl_elem itr; 1955 pvl_elem itr;
1873 pvl_list days = expand_by_day(impl,year); 1956 pvl_list days = expand_by_day(impl,year);
1874 1957
1875 for(itr=pvl_head(days);itr!=0;itr=pvl_next(itr)){ 1958 for(itr=pvl_head(days);itr!=0;itr=pvl_next(itr)){
1876 short day = (short)(int)pvl_data(itr); 1959 short day = (short)(*((int*)pvl_data(itr)));
1877 struct icaltimetype tt; 1960 struct icaltimetype tt;
1878 short j;
1879 1961
1880 tt = icaltime_from_day_of_year(day,year); 1962 tt = icaltime_from_day_of_year(day,year);
1881 1963
1882 for(j = 0; BYMDPTR[j]!=ICAL_RECURRENCE_ARRAY_MAX; j++){ 1964 for(j = 0; BYMDPTR[j]!=ICAL_RECURRENCE_ARRAY_MAX; j++){
1883 short mday = BYMDPTR[j]; 1965 int mday = BYMDPTR[j];
1884 1966
1885 if(tt.day == mday){ 1967 if(tt.day == mday){
1886 impl->days[days_index++] = day; 1968 impl->days[days_index++] = day;
1887 } 1969 }
1888 } 1970 }
1889 1971
1890 } 1972 }
1891 1973
1892 pvl_free(days); 1974 pvl_free(days);
1893 1975
1894 break; 1976 break;
1895 } 1977 }
1896 1978
1897 case (1<<BY_DAY) + (1<<BY_MONTH_DAY) + (1<<BY_MONTH): { 1979 case (1<<BY_DAY) + (1<<BY_MONTH_DAY) + (1<<BY_MONTH): {
1898 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; BYMONTHDAY=10; MYMONTH=6,11*/ 1980 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; BYMONTHDAY=10; MYMONTH=6,11*/
1899 1981
1900 int days_index = 0;
1901 pvl_elem itr; 1982 pvl_elem itr;
1902 pvl_list days = expand_by_day(impl,year); 1983 pvl_list days = expand_by_day(impl,year);
1903 1984
1904 for(itr=pvl_head(days);itr!=0;itr=pvl_next(itr)){ 1985 for(itr=pvl_head(days);itr!=0;itr=pvl_next(itr)){
1905 short day = (short)(int)pvl_data(itr); 1986 short day = (short)(*((int*)pvl_data(itr)));
1906 struct icaltimetype tt; 1987 struct icaltimetype tt;
1907 short i,j; 1988 int i;
1908 1989
1909 tt = icaltime_from_day_of_year(day,year); 1990 tt = icaltime_from_day_of_year(day,year);
1910 1991
1911 for(i = 0; BYMONPTR[i] != ICAL_RECURRENCE_ARRAY_MAX; i++){ 1992 for(i = 0; BYMONPTR[i] != ICAL_RECURRENCE_ARRAY_MAX; i++){
1912 for(j = 0; BYMDPTR[j]!=ICAL_RECURRENCE_ARRAY_MAX; j++){ 1993 for(j = 0; BYMDPTR[j]!=ICAL_RECURRENCE_ARRAY_MAX; j++){
1913 short mday = BYMDPTR[j]; 1994 int mday = BYMDPTR[j];
1914 short month = BYMONPTR[i]; 1995 int month = BYMONPTR[i];
1915 1996
1916 if(tt.month == month && tt.day == mday){ 1997 if(tt.month == month && tt.day == mday){
1917 impl->days[days_index++] = day; 1998 impl->days[days_index++] = day;
1918 } 1999 }
1919 } 2000 }
1920 } 2001 }
1921 2002
1922 } 2003 }
1923 2004
1924 pvl_free(days); 2005 pvl_free(days);
1925 2006
1926 break; 2007 break;
1927 2008
1928 } 2009 }
1929 2010
1930 case (1<<BY_DAY) + (1<<BY_WEEK_NO) : { 2011 case (1<<BY_DAY) + (1<<BY_WEEK_NO) : {
1931 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; WEEKNO=20,50*/ 2012 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; WEEKNO=20,50*/
1932 2013
1933 int days_index = 0;
1934 pvl_elem itr; 2014 pvl_elem itr;
1935 pvl_list days = expand_by_day(impl,year); 2015 pvl_list days = expand_by_day(impl,year);
1936 2016
1937 for(itr=pvl_head(days);itr!=0;itr=pvl_next(itr)){ 2017 for(itr=pvl_head(days);itr!=0;itr=pvl_next(itr)){
1938 short day = (short)(int)pvl_data(itr); 2018 short day = (short)(*((int*)pvl_data(itr)));
1939 struct icaltimetype tt; 2019 struct icaltimetype tt;
1940 short i; 2020 int i;
1941 2021
1942 tt = icaltime_from_day_of_year(day,year); 2022 tt = icaltime_from_day_of_year(day,year);
1943 2023
1944 for(i = 0; BYWEEKPTR[i] != ICAL_RECURRENCE_ARRAY_MAX; i++){ 2024 for(i = 0; BYWEEKPTR[i] != ICAL_RECURRENCE_ARRAY_MAX; i++){
1945 short weekno = BYWEEKPTR[i]; 2025 int weekno = BYWEEKPTR[i];
1946 2026 int this_weekno = icaltime_week_number(tt);
1947 if(weekno== icaltime_week_number(tt)){ 2027 if(weekno== this_weekno){
1948 impl->days[days_index++] = day; 2028 impl->days[days_index++] = day;
1949 } 2029 }
1950 } 2030 }
1951 2031
1952 } 2032 }
1953 2033
1954 pvl_free(days); 2034 pvl_free(days);
1955 break; 2035 break;
1956 } 2036 }
1957 2037
1958 case (1<<BY_DAY) + (1<<BY_WEEK_NO) + (1<<BY_MONTH_DAY): { 2038 case (1<<BY_DAY) + (1<<BY_WEEK_NO) + (1<<BY_MONTH_DAY): {
1959 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; WEEKNO=20,50; BYMONTHDAY=1,15*/ 2039 /*FREQ=YEARLY; BYDAY=TH,20MO,-10FR; WEEKNO=20,50; BYMONTHDAY=1,15*/
1960 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); 2040 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
1961 break; 2041 break;
1962 } 2042 }
1963 2043
1964 case 1<<BY_YEAR_DAY: { 2044 case 1<<BY_YEAR_DAY: {
1965 for(j=0;impl->by_ptrs[BY_YEAR_DAY][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){ 2045 for(j=0;impl->by_ptrs[BY_YEAR_DAY][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){
1966 short doy = impl->by_ptrs[BY_YEAR_DAY][j]; 2046 impl->days[days_index++] = impl->by_ptrs[BY_YEAR_DAY][j];
1967 impl->days[days_index++] = doy;
1968 } 2047 }
1969 break; 2048 break;
1970 } 2049 }
1971 2050
1972 default: { 2051 default: {
1973 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); 2052 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
1974 break; 2053 break;
1975 } 2054 }
1976 2055
1977 } 2056 }
1978 2057
1979 return 0; 2058 return 0;
1980} 2059}
1981 2060
1982 2061
1983int next_year(struct icalrecur_iterator_impl* impl) 2062static int next_year(icalrecur_iterator* impl)
1984{ 2063{
1985 struct icaltimetype next; 2064 struct icaltimetype next;
1986 2065
1987 /* Next_year does it's own interatio in days, so the next level down is hours */
1988 if (next_hour(impl) == 0){ 2066 if (next_hour(impl) == 0){
1989 return 1; 2067 return 0;
1990 } 2068 }
1991 2069
1992 if (impl->days[++impl->days_index] == ICAL_RECURRENCE_ARRAY_MAX){ 2070 if (impl->days[++impl->days_index] == ICAL_RECURRENCE_ARRAY_MAX){
1993 impl->days_index = 0; 2071 impl->days_index = 0;
2072
2073 for (;;) {
1994 increment_year(impl,impl->rule.interval); 2074 increment_year(impl,impl->rule.interval);
1995 expand_year_days(impl,impl->last.year); 2075 expand_year_days(impl,impl->last.year);
2076 if (impl->days[0] != ICAL_RECURRENCE_ARRAY_MAX)
2077 break;
1996 } 2078 }
1997
1998 if(impl->days[0] == ICAL_RECURRENCE_ARRAY_MAX) {
1999 return 0;
2000 } 2079 }
2001 2080
2002 next = icaltime_from_day_of_year(impl->days[impl->days_index],impl->last.year); 2081 next = icaltime_from_day_of_year(impl->days[impl->days_index],impl->last.year);
2003 2082
2004 impl->last.day = next.day; 2083 impl->last.day = next.day;
2005 impl->last.month = next.month; 2084 impl->last.month = next.month;
2006 2085
2007 return 1; 2086 return 1;
2008} 2087}
2009 2088
2010int icalrecur_check_rulepart(struct icalrecur_iterator_impl* impl, 2089int icalrecur_check_rulepart(icalrecur_iterator* impl,
2011 short v, enum byrule byrule) 2090 int v, enum byrule byrule)
2012{ 2091{
2013 int itr; 2092 int itr;
2014 2093
2015 if(impl->by_ptrs[byrule][0]!=ICAL_RECURRENCE_ARRAY_MAX){ 2094 if(impl->by_ptrs[byrule][0]!=ICAL_RECURRENCE_ARRAY_MAX){
2016 for(itr=0; impl->by_ptrs[byrule][itr]!=ICAL_RECURRENCE_ARRAY_MAX;itr++){ 2095 for(itr=0; impl->by_ptrs[byrule][itr]!=ICAL_RECURRENCE_ARRAY_MAX;itr++){
2017 if(impl->by_ptrs[byrule][itr] == v){ 2096 if(impl->by_ptrs[byrule][itr] == v){
2018 return 1; 2097 return 1;
2019 } 2098 }
2020 } 2099 }
2021 } 2100 }
2022 2101
2023 return 0; 2102 return 0;
2024} 2103}
2025 2104
2026int check_contract_restriction(struct icalrecur_iterator_impl* impl, 2105static int check_contract_restriction(icalrecur_iterator* impl,
2027 enum byrule byrule, short v) 2106 enum byrule byrule, int v)
2028{ 2107{
2029 int pass = 0; 2108 int pass = 0;
2030 int itr; 2109 int itr;
2031 icalrecurrencetype_frequency freq = impl->rule.freq; 2110 icalrecurrencetype_frequency freq = impl->rule.freq;
2032 2111
2033 if(impl->by_ptrs[byrule][0]!=ICAL_RECURRENCE_ARRAY_MAX && 2112 if(impl->by_ptrs[byrule][0]!=ICAL_RECURRENCE_ARRAY_MAX &&
2034 expand_map[freq].map[byrule] == CONTRACT){ 2113 expand_map[freq].map[byrule] == CONTRACT){
2035 for(itr=0; impl->by_ptrs[byrule][itr]!=ICAL_RECURRENCE_ARRAY_MAX;itr++){ 2114 for(itr=0; impl->by_ptrs[byrule][itr]!=ICAL_RECURRENCE_ARRAY_MAX;itr++){
2036 if(impl->by_ptrs[byrule][itr] == v){ 2115 if(impl->by_ptrs[byrule][itr] == v){
2037 pass=1; 2116 pass=1;
2038 break; 2117 break;
2039 } 2118 }
2040 } 2119 }
2041 2120
2042 return pass; 2121 return pass;
2043 } else { 2122 } else {
2044 /* This is not a contracting byrule, or it has no data, so the 2123 /* This is not a contracting byrule, or it has no data, so the
2045 test passes*/ 2124 test passes*/
2046 return 1; 2125 return 1;
2047 } 2126 }
2048} 2127}
2049 2128
2050 2129
2051int check_contracting_rules(struct icalrecur_iterator_impl* impl) 2130static int check_contracting_rules(icalrecur_iterator* impl)
2052{ 2131{
2053 2132
2054 int day_of_week=0; 2133 int day_of_week = icaltime_day_of_week(impl->last);
2055 int week_no=0; 2134 int week_no = icaltime_week_number(impl->last);
2056 int year_day=0; 2135 int year_day = icaltime_day_of_year(impl->last);
2057 2136
2058 if ( 2137 if (
2059 check_contract_restriction(impl,BY_SECOND,impl->last.second) && 2138 check_contract_restriction(impl,BY_SECOND,impl->last.second) &&
2060 check_contract_restriction(impl,BY_MINUTE,impl->last.minute) && 2139 check_contract_restriction(impl,BY_MINUTE,impl->last.minute) &&
2061 check_contract_restriction(impl,BY_HOUR,impl->last.hour) && 2140 check_contract_restriction(impl,BY_HOUR,impl->last.hour) &&
2062 check_contract_restriction(impl,BY_DAY,day_of_week) && 2141 check_contract_restriction(impl,BY_DAY,day_of_week) &&
2063 check_contract_restriction(impl,BY_WEEK_NO,week_no) && 2142 check_contract_restriction(impl,BY_WEEK_NO,week_no) &&
2064 check_contract_restriction(impl,BY_MONTH_DAY,impl->last.day) && 2143 check_contract_restriction(impl,BY_MONTH_DAY,impl->last.day) &&
2065 check_contract_restriction(impl,BY_MONTH,impl->last.month) && 2144 check_contract_restriction(impl,BY_MONTH,impl->last.month) &&
2066 check_contract_restriction(impl,BY_YEAR_DAY,year_day) ) 2145 check_contract_restriction(impl,BY_YEAR_DAY,year_day) )
2067 { 2146 {
2068 2147
2069 return 1; 2148 return 1;
2070 } else { 2149 } else {
2071 return 0; 2150 return 0;
2072 } 2151 }
2073} 2152}
2074 2153
2075struct icaltimetype icalrecur_iterator_next(icalrecur_iterator *itr) 2154struct icaltimetype icalrecur_iterator_next(icalrecur_iterator *impl)
2076{ 2155{
2077 int valid = 1; 2156 int valid = 1;
2078 struct icalrecur_iterator_impl* impl =
2079 (struct icalrecur_iterator_impl*)itr;
2080 2157
2081 if( (impl->rule.count!=0 &&impl->occurrence_no >= impl->rule.count) || 2158 if( (impl->rule.count!=0 &&impl->occurrence_no >= impl->rule.count) ||
2082 (!icaltime_is_null_time(impl->rule.until) && 2159 (!icaltime_is_null_time(impl->rule.until) &&
2083 icaltime_compare(impl->last,impl->rule.until) > 0)) { 2160 icaltime_compare(impl->last,impl->rule.until) > 0)) {
2084 return icaltime_null_time(); 2161 return icaltime_null_time();
2085 } 2162 }
2086 2163
2087 if(impl->occurrence_no == 0 2164 if(impl->occurrence_no == 0
2088 && icaltime_compare(impl->last,impl->dtstart) >= 0){ 2165 && icaltime_compare(impl->last,impl->dtstart) >= 0){
2089 2166
2090 impl->occurrence_no++; 2167 impl->occurrence_no++;
2091 return impl->last; 2168 return impl->last;
2092 } 2169 }
2093 2170
2094 do { 2171 do {
2095 valid = 1; 2172 valid = 1;
2096 switch(impl->rule.freq){ 2173 switch(impl->rule.freq){
2097 2174
2098 case ICAL_SECONDLY_RECURRENCE: { 2175 case ICAL_SECONDLY_RECURRENCE: {
2099 next_second(impl); 2176 next_second(impl);
2100 break; 2177 break;
2101 } 2178 }
2102 case ICAL_MINUTELY_RECURRENCE: { 2179 case ICAL_MINUTELY_RECURRENCE: {
2103 next_minute(impl); 2180 next_minute(impl);
2104 break; 2181 break;
2105 } 2182 }
2106 case ICAL_HOURLY_RECURRENCE: { 2183 case ICAL_HOURLY_RECURRENCE: {
2107 next_hour(impl); 2184 next_hour(impl);
2108 break; 2185 break;
2109 } 2186 }
2110 case ICAL_DAILY_RECURRENCE: { 2187 case ICAL_DAILY_RECURRENCE: {
2111 next_day(impl); 2188 next_day(impl);
2112 break; 2189 break;
2113 } 2190 }
2114 case ICAL_WEEKLY_RECURRENCE: { 2191 case ICAL_WEEKLY_RECURRENCE: {
2115 next_week(impl); 2192 next_week(impl);
2116 break; 2193 break;
2117 } 2194 }
2118 case ICAL_MONTHLY_RECURRENCE: { 2195 case ICAL_MONTHLY_RECURRENCE: {
2119 valid = next_month(impl); 2196 valid = next_month(impl);
2120 break; 2197 break;
2121 } 2198 }
2122 case ICAL_YEARLY_RECURRENCE:{ 2199 case ICAL_YEARLY_RECURRENCE:{
2123 valid = next_year(impl); 2200 next_year(impl);
2124 break; 2201 break;
2125 } 2202 }
2126 default:{ 2203 default:{
2127 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 2204 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
2128 return icaltime_null_time(); 2205 return icaltime_null_time();
2129 } 2206 }
2130 } 2207 }
2131 2208
2132 if(impl->last.year >= 2038 ){ 2209 if(impl->last.year >= 2038 ){
2133 /* HACK */ 2210 /* HACK */
2134 return icaltime_null_time(); 2211 return icaltime_null_time();
2135 } 2212 }
2136 2213
2137 } while(!check_contracting_rules(impl) 2214 } while(!check_contracting_rules(impl)
2138 || icaltime_compare(impl->last,impl->dtstart) <= 0 2215 || icaltime_compare(impl->last,impl->dtstart) < 0
2139 || valid == 0); 2216 || valid == 0);
2140 2217
2141 2218
2142/* Ignore null times and times that are after the until time */ 2219/* Ignore null times and times that are after the until time */
2143 if( !icaltime_is_null_time(impl->rule.until) && 2220 if( !icaltime_is_null_time(impl->rule.until) &&
2144 icaltime_compare(impl->last,impl->rule.until) > 0 ) { 2221 icaltime_compare(impl->last,impl->rule.until) > 0 ) {
2145 return icaltime_null_time(); 2222 return icaltime_null_time();
2146 } 2223 }
2147 2224
2148 impl->occurrence_no++; 2225 impl->occurrence_no++;
2149 2226
2150 return impl->last; 2227 return impl->last;
2151} 2228}
2152 2229
2153 2230
2154/************************** Type Routines **********************/ 2231/************************** Type Routines **********************/
2155 2232
2156 2233
2157void icalrecurrencetype_clear(struct icalrecurrencetype *recur) 2234void icalrecurrencetype_clear(struct icalrecurrencetype *recur)
2158{ 2235{
2159 memset(recur,ICAL_RECURRENCE_ARRAY_MAX_BYTE, 2236 memset(recur,ICAL_RECURRENCE_ARRAY_MAX_BYTE,
2160 sizeof(struct icalrecurrencetype)); 2237 sizeof(struct icalrecurrencetype));
2161 2238
2162 recur->week_start = ICAL_MONDAY_WEEKDAY; 2239 recur->week_start = ICAL_MONDAY_WEEKDAY;
2163 recur->freq = ICAL_NO_RECURRENCE; 2240 recur->freq = ICAL_NO_RECURRENCE;
2164 recur->interval = 1; 2241 recur->interval = 1;
2165 memset(&(recur->until),0,sizeof(struct icaltimetype)); 2242 memset(&(recur->until),0,sizeof(struct icaltimetype));
2166 recur->count = 0; 2243 recur->count = 0;
2167} 2244}
2168 2245
2169/* The 'day' element of icalrecurrencetype_weekday is encoded to allow 2246/** The 'day' element of icalrecurrencetype_weekday is encoded to
2170reporesentation of both the day of the week ( Monday, Tueday), but 2247 * allow representation of both the day of the week ( Monday, Tueday),
2171also the Nth day of the week ( First tuesday of the month, last 2248 * but also the Nth day of the week ( First tuesday of the month, last
2172thursday of the year) These routines decode the day values. 2249 * thursday of the year) These routines decode the day values.
2173 2250 *
2174The day's position in the period ( Nth-ness) and the numerical value 2251 * The day's position in the period ( Nth-ness) and the numerical
2175of the day are encoded together as: pos*7 + dow 2252 * value of the day are encoded together as: pos*7 + dow
2176 2253 *
2177A position of 0 means 'any' or 'every' 2254 * A position of 0 means 'any' or 'every'
2178
2179 */ 2255 */
2180 2256
2181enum icalrecurrencetype_weekday icalrecurrencetype_day_day_of_week(short day) 2257enum icalrecurrencetype_weekday icalrecurrencetype_day_day_of_week(short day)
2182{ 2258{
2183 return abs(day)%8; 2259 return abs(day)%8;
2184} 2260}
2185 2261
2186short icalrecurrencetype_day_position(short day) 2262int icalrecurrencetype_day_position(short day)
2187{ 2263{
2188 short wd, pos; 2264 int wd, pos;
2189 2265
2190 wd = icalrecurrencetype_day_day_of_week(day); 2266 wd = icalrecurrencetype_day_day_of_week(day);
2191 2267
2192 pos = (abs(day)-wd)/8 * ((day<0)?-1:1); 2268 pos = (abs(day)-wd)/8 * ((day<0)?-1:1);
2193 2269
2194 2270
2195 return pos; 2271 return pos;
2196} 2272}
2197 2273
2198 2274
2199/****************** Enumeration Routines ******************/ 2275/****************** Enumeration Routines ******************/
2200 2276
2201struct {icalrecurrencetype_weekday wd; const char * str; } 2277static struct {icalrecurrencetype_weekday wd; const char * str; }
2202wd_map[] = { 2278wd_map[] = {
2203 {ICAL_SUNDAY_WEEKDAY,"SU"}, 2279 {ICAL_SUNDAY_WEEKDAY,"SU"},
2204 {ICAL_MONDAY_WEEKDAY,"MO"}, 2280 {ICAL_MONDAY_WEEKDAY,"MO"},
2205 {ICAL_TUESDAY_WEEKDAY,"TU"}, 2281 {ICAL_TUESDAY_WEEKDAY,"TU"},
2206 {ICAL_WEDNESDAY_WEEKDAY,"WE"}, 2282 {ICAL_WEDNESDAY_WEEKDAY,"WE"},
2207 {ICAL_THURSDAY_WEEKDAY,"TH"}, 2283 {ICAL_THURSDAY_WEEKDAY,"TH"},
2208 {ICAL_FRIDAY_WEEKDAY,"FR"}, 2284 {ICAL_FRIDAY_WEEKDAY,"FR"},
2209 {ICAL_SATURDAY_WEEKDAY,"SA"}, 2285 {ICAL_SATURDAY_WEEKDAY,"SA"},
2210 {ICAL_NO_WEEKDAY,0} 2286 {ICAL_NO_WEEKDAY,0}
2211}; 2287};
2212 2288
2213const char* icalrecur_weekday_to_string(icalrecurrencetype_weekday kind) 2289const char* icalrecur_weekday_to_string(icalrecurrencetype_weekday kind)
2214{ 2290{
2215 int i; 2291 int i;
2216 2292
2217 for (i=0; wd_map[i].wd != ICAL_NO_WEEKDAY; i++) { 2293 for (i=0; wd_map[i].wd != ICAL_NO_WEEKDAY; i++) {
2218 if ( wd_map[i].wd == kind) { 2294 if ( wd_map[i].wd == kind) {
2219 return wd_map[i].str; 2295 return wd_map[i].str;
2220 } 2296 }
2221 } 2297 }
2222 2298
2223 return 0; 2299 return 0;
2224} 2300}
2225 2301
2226icalrecurrencetype_weekday icalrecur_string_to_weekday(const char* str) 2302icalrecurrencetype_weekday icalrecur_string_to_weekday(const char* str)
2227{ 2303{
2228 int i; 2304 int i;
2229 2305
2230 for (i=0; wd_map[i].wd != ICAL_NO_WEEKDAY; i++) { 2306 for (i=0; wd_map[i].wd != ICAL_NO_WEEKDAY; i++) {
2231 if ( strcmp(str,wd_map[i].str) == 0){ 2307 if ( strcmp(str,wd_map[i].str) == 0){
2232 return wd_map[i].wd; 2308 return wd_map[i].wd;
2233 } 2309 }
2234 } 2310 }
2235 2311
2236 return ICAL_NO_WEEKDAY; 2312 return ICAL_NO_WEEKDAY;
2237} 2313}
2238 2314
2239 2315
2240 2316
2241struct { 2317static struct {
2242 icalrecurrencetype_frequency kind; 2318 icalrecurrencetype_frequency kind;
2243 const char* str; 2319 const char* str;
2244} freq_map[] = { 2320} freq_map[] = {
2245 {ICAL_SECONDLY_RECURRENCE,"SECONDLY"}, 2321 {ICAL_SECONDLY_RECURRENCE,"SECONDLY"},
2246 {ICAL_MINUTELY_RECURRENCE,"MINUTELY"}, 2322 {ICAL_MINUTELY_RECURRENCE,"MINUTELY"},
2247 {ICAL_HOURLY_RECURRENCE,"HOURLY"}, 2323 {ICAL_HOURLY_RECURRENCE,"HOURLY"},
2248 {ICAL_DAILY_RECURRENCE,"DAILY"}, 2324 {ICAL_DAILY_RECURRENCE,"DAILY"},
2249 {ICAL_WEEKLY_RECURRENCE,"WEEKLY"}, 2325 {ICAL_WEEKLY_RECURRENCE,"WEEKLY"},
2250 {ICAL_MONTHLY_RECURRENCE,"MONTHLY"}, 2326 {ICAL_MONTHLY_RECURRENCE,"MONTHLY"},
2251 {ICAL_YEARLY_RECURRENCE,"YEARLY"}, 2327 {ICAL_YEARLY_RECURRENCE,"YEARLY"},
2252 {ICAL_NO_RECURRENCE,0} 2328 {ICAL_NO_RECURRENCE,0}
2253}; 2329};
2254 2330
2255const char* icalrecur_freq_to_string(icalrecurrencetype_frequency kind) 2331const char* icalrecur_freq_to_string(icalrecurrencetype_frequency kind)
2256{ 2332{
2257 int i; 2333 int i;
2258 2334
2259 for (i=0; freq_map[i].kind != ICAL_NO_RECURRENCE ; i++) { 2335 for (i=0; freq_map[i].kind != ICAL_NO_RECURRENCE ; i++) {
2260 if ( freq_map[i].kind == kind ) { 2336 if ( freq_map[i].kind == kind ) {
2261 return freq_map[i].str; 2337 return freq_map[i].str;
2262 } 2338 }
2263 } 2339 }
2264 return 0; 2340 return 0;
2265} 2341}
2266 2342
2267icalrecurrencetype_frequency icalrecur_string_to_freq(const char* str) 2343icalrecurrencetype_frequency icalrecur_string_to_freq(const char* str)
2268{ 2344{
2269 int i; 2345 int i;
2270 2346
2271 for (i=0; freq_map[i].kind != ICAL_NO_RECURRENCE ; i++) { 2347 for (i=0; freq_map[i].kind != ICAL_NO_RECURRENCE ; i++) {
2272 if ( strcmp(str,freq_map[i].str) == 0){ 2348 if ( strcmp(str,freq_map[i].str) == 0){
2273 return freq_map[i].kind; 2349 return freq_map[i].kind;
2274 } 2350 }
2275 } 2351 }
2276 return ICAL_NO_RECURRENCE; 2352 return ICAL_NO_RECURRENCE;
2277} 2353}
2278 2354
2279/* Fill an array with the 'count' number of occurrences generated by 2355/** Fill an array with the 'count' number of occurrences generated by
2280 the rrule. Note that the times are returned in UTC, but the times 2356 * the rrule. Note that the times are returned in UTC, but the times
2281 are calculated in local time. YOu will have to convert the results 2357 * are calculated in local time. YOu will have to convert the results
2282 back into local time before using them. */ 2358 * back into local time before using them.
2359 */
2283 2360
2284int icalrecur_expand_recurrence(char* rule, time_t start, 2361int icalrecur_expand_recurrence(char* rule, time_t start,
2285 int count, time_t* array) 2362 int count, time_t* array)
2286{ 2363{
2287 struct icalrecurrencetype recur; 2364 struct icalrecurrencetype recur;
2288 icalrecur_iterator* ritr; 2365 icalrecur_iterator* ritr;
2289 time_t tt; 2366 time_t tt;
2290 struct icaltimetype icstart, next; 2367 struct icaltimetype icstart, next;
2291 int i = 0; 2368 int i = 0;
2292 2369
2293 memset(array, 0, count*sizeof(time_t)); 2370 memset(array, 0, count*sizeof(time_t));
2294 2371
2295 icstart = icaltime_from_timet(start,0); 2372 icstart = icaltime_from_timet_with_zone(start,0,0);
2296 2373
2297 recur = icalrecurrencetype_from_string(rule); 2374 recur = icalrecurrencetype_from_string(rule);
2298 2375
2299 for(ritr = icalrecur_iterator_new(recur,icstart), 2376 for(ritr = icalrecur_iterator_new(recur,icstart),
2300 next = icalrecur_iterator_next(ritr); 2377 next = icalrecur_iterator_next(ritr);
2301 !icaltime_is_null_time(next) && i < count; 2378 !icaltime_is_null_time(next) && i < count;
2302 next = icalrecur_iterator_next(ritr)){ 2379 next = icalrecur_iterator_next(ritr)){
2303 2380
2304 tt = icaltime_as_timet(next); 2381 tt = icaltime_as_timet(next);
2305 2382
2306 if (tt >= start ){ 2383 if (tt >= start ){
2307 array[i++] = tt; 2384 array[i++] = tt;
2308 } 2385 }
2309 2386
2310 } 2387 }
2311 2388
2312 icalrecur_iterator_free(ritr); 2389 icalrecur_iterator_free(ritr);
2313 2390
2314 return 1; 2391 return 1;
2315} 2392}