summaryrefslogtreecommitdiffabout
path: root/libical/src/libical/icalrecur.c
Unidiff
Diffstat (limited to 'libical/src/libical/icalrecur.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libical/src/libical/icalrecur.c789
1 files changed, 433 insertions, 356 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
@@ -19,7 +19,11 @@
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
@@ -130,15 +134,14 @@
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 */
@@ -148,6 +151,10 @@
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
@@ -170,7 +177,6 @@ const 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 {
@@ -253,7 +259,7 @@ void icalrecur_add_byrules(struct icalrecur_parser *parser, short *array,
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
@@ -280,12 +286,14 @@ void icalrecur_add_byrules(struct icalrecur_parser *parser, short *array,
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 }
@@ -332,21 +340,18 @@ void icalrecur_add_bydayrules(struct icalrecur_parser *parser, const char* vals)
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 }
@@ -387,6 +392,7 @@ struct icalrecurrencetype icalrecurrencetype_from_string(const char* str)
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
@@ -397,7 +403,7 @@ struct icalrecurrencetype icalrecurrencetype_from_string(const char* str)
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){
@@ -429,6 +435,7 @@ struct icalrecurrencetype icalrecurrencetype_from_string(const char* str)
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
@@ -440,9 +447,7 @@ struct icalrecurrencetype icalrecurrencetype_from_string(const char* str)
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},
@@ -457,6 +462,7 @@ struct { char* str;size_t offset; short limit; } recurmap[] =
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)
@@ -481,7 +487,10 @@ char* icalrecurrencetype_as_string(struct icalrecurrencetype *recur)
481 if(recur->until.year != 0){ 487 if(recur->until.year != 0){
482 488
483 temp[0] = 0; 489 temp[0] = 0;
484 print_datetime_to_string(temp,&(recur->until)); 490 if (recur->until.is_date)
491 print_date_to_string(temp,&(recur->until));
492 else
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);
@@ -501,7 +510,7 @@ char* icalrecurrencetype_as_string(struct icalrecurrencetype *recur)
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 ) {
@@ -512,9 +521,9 @@ char* icalrecurrencetype_as_string(struct icalrecurrencetype *recur)
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
@@ -540,8 +549,6 @@ char* icalrecurrencetype_as_string(struct icalrecurrencetype *recur)
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 ******************/
@@ -573,13 +580,15 @@ struct icalrecur_iterator_impl {
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;
@@ -599,10 +608,13 @@ enum expand_table {
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;
@@ -613,7 +625,7 @@ struct expand_split_map_struct
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}},
@@ -628,15 +640,16 @@ struct expand_split_map_struct expand_map[] =
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;
@@ -659,8 +672,8 @@ int icalrecur_two_byrule(struct icalrecur_iterator_impl* impl,
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;
@@ -676,7 +689,7 @@ int icalrecur_one_byrule(struct icalrecur_iterator_impl* impl,enum byrule one)
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;
@@ -691,9 +704,9 @@ int count_byrules(struct icalrecur_iterator_impl* impl)
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;
@@ -704,7 +717,7 @@ void setup_defaults(struct icalrecur_iterator_impl* impl,
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 */
@@ -715,30 +728,28 @@ void setup_defaults(struct icalrecur_iterator_impl* impl,
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;
@@ -760,7 +771,7 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
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
@@ -768,23 +779,23 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
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 */
@@ -852,19 +863,24 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
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
@@ -874,7 +890,7 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
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
@@ -888,7 +904,7 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
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 */
@@ -901,10 +917,24 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
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){
907 expand_year_days(impl,impl->last.year); 924 struct icaltimetype next;
925
926 for (;;) {
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
@@ -914,13 +944,13 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
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){
@@ -969,26 +999,21 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
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
@@ -1035,14 +1060,14 @@ void increment_month(struct icalrecur_iterator_impl* impl)
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
@@ -1054,9 +1079,9 @@ void increment_monthday(struct icalrecur_iterator_impl* impl, int inc)
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
@@ -1068,9 +1093,9 @@ void increment_hour(struct icalrecur_iterator_impl* impl, int inc)
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
@@ -1083,9 +1108,9 @@ void increment_minute(struct icalrecur_iterator_impl* impl, int inc)
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
@@ -1102,7 +1127,7 @@ void increment_second(struct icalrecur_iterator_impl* impl, int inc)
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
@@ -1132,17 +1157,17 @@ void test_increment()
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]++;
@@ -1159,7 +1184,7 @@ short next_second(struct icalrecur_iterator_impl* impl)
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
@@ -1168,7 +1193,7 @@ short next_second(struct icalrecur_iterator_impl* impl)
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
@@ -1176,22 +1201,22 @@ short next_second(struct icalrecur_iterator_impl* impl)
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]++;
@@ -1207,7 +1232,7 @@ int next_minute(struct icalrecur_iterator_impl* impl)
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 }
@@ -1215,28 +1240,28 @@ int next_minute(struct icalrecur_iterator_impl* impl)
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]++;
@@ -1251,7 +1276,7 @@ int next_hour(struct icalrecur_iterator_impl* impl)
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
@@ -1260,7 +1285,7 @@ int next_hour(struct icalrecur_iterator_impl* impl)
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
@@ -1268,13 +1293,13 @@ int next_hour(struct icalrecur_iterator_impl* impl)
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;
@@ -1296,14 +1321,14 @@ int next_day(struct icalrecur_iterator_impl* impl)
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;
@@ -1321,7 +1346,7 @@ int next_yearday(struct icalrecur_iterator_impl* impl)
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
@@ -1329,62 +1354,15 @@ int next_yearday(struct icalrecur_iterator_impl* impl)
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
1365 dow--; /*Sun is 1, not 0 */
1366
1367 if(dow+start_of_week <1 && !end_of_data){
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
1374 impl->last.day = next.day;
1375 impl->last.month = next.month;
1376 impl->last.year = next.year;
1377
1378 return end_of_data;
1379 }
1380 1357
1381} 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 */
1382 1360
1383int nth_weekday(short dow, short pos, struct icaltimetype t){ 1361static int nth_weekday(int dow, int pos, struct icaltimetype t){
1384 1362
1385 short days_in_month = icaltime_days_in_month(t.month,t.year); 1363 int days_in_month = icaltime_days_in_month(t.month, t.year);
1386 short end_dow, start_dow; 1364 int end_dow, start_dow;
1387 short wd; 1365 int wd;
1388 1366
1389 if(pos >= 0){ 1367 if(pos >= 0){
1390 t.day = 1; 1368 t.day = 1;
@@ -1428,12 +1406,29 @@ int nth_weekday(short dow, short pos, struct icaltimetype t){
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;
1431 1412
1432int next_month(struct icalrecur_iterator_impl* impl) 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}
1426
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
@@ -1445,14 +1440,17 @@ int next_month(struct icalrecur_iterator_impl* impl)
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. */
1445
1446 /*
1447 * Case 1:
1448 * Rules Like: FREQ=MONTHLY;INTERVAL=1;BYDAY=FR;BYMONTHDAY=13
1449 */
1451 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
@@ -1463,11 +1461,11 @@ int next_month(struct icalrecur_iterator_impl* impl)
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);
@@ -1488,51 +1486,57 @@ int next_month(struct icalrecur_iterator_impl* 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 impl->last.day = day;
1511 short dow = icalrecurrencetype_day_day_of_week(BYDAYPTR[idx]); 1512 if(is_day_in_byday(impl,impl->last)){
1512 short pos = icalrecurrencetype_day_position(BYDAYPTR[idx]); 1513 data_valid = 1;
1513 short this_dow; 1514 break;
1514
1515 impl->last.day = day;
1516 this_dow = icaltime_day_of_week(impl->last);
1517
1518 if( (pos == 0 && dow == this_dow ) ||
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);
1530 data_valid = 0; /* signal that impl->last is invalid */ 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 {
1529 data_valid = 0; /* signal that impl->last is invalid */
1530 }
1531 } 1531 }
1532 1532
1533 /*
1534 * Case 3
1535 * Rules Like: FREQ=MONTHLY;COUNT=10;BYMONTHDAY=-3
1536 */
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
@@ -1548,8 +1552,7 @@ int next_month(struct icalrecur_iterator_impl* impl)
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;
@@ -1558,18 +1561,72 @@ int next_month(struct icalrecur_iterator_impl* impl)
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;
1562 1565
1563} 1566}
1564 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;
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;
1611 }
1612 }
1613
1614 next = icaltime_from_day_of_year(start_of_week + dow,impl->last.year);
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 }
1622
1623}
1565 1624
1566int next_week(struct icalrecur_iterator_impl* impl) 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 }
@@ -1577,8 +1634,8 @@ int next_week(struct icalrecur_iterator_impl* impl)
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;
@@ -1602,13 +1659,12 @@ int next_week(struct icalrecur_iterator_impl* impl)
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
@@ -1616,14 +1672,14 @@ int next_week(struct icalrecur_iterator_impl* impl)
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;
@@ -1631,37 +1687,35 @@ pvl_list expand_by_day(struct icalrecur_iterator_impl* impl,short year)
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 */
@@ -1671,7 +1725,7 @@ pvl_list expand_by_day(struct icalrecur_iterator_impl* impl,short year)
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 */
@@ -1696,22 +1750,23 @@ pvl_list expand_by_day(struct icalrecur_iterator_impl* impl,short year)
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) +
@@ -1723,16 +1778,19 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
1723 1778
1724 case 0: { 1779 case 0: {
1725 /* FREQ=YEARLY; */ 1780 /* FREQ=YEARLY; */
1781 t = impl->dtstart;
1782 t.year = impl->last.year;
1726 1783
1784 impl->days[days_index++] = (short)icaltime_day_of_year(t);
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;
@@ -1741,7 +1799,7 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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;
@@ -1751,8 +1809,8 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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;
@@ -1761,7 +1819,7 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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;
@@ -1773,9 +1831,9 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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;
@@ -1784,7 +1842,7 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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 }
@@ -1795,8 +1853,7 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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;
@@ -1819,13 +1876,12 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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
@@ -1837,50 +1893,76 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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;
@@ -1897,21 +1979,20 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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;
@@ -1930,21 +2011,20 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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 }
@@ -1963,8 +2043,7 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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 }
@@ -1980,26 +2059,26 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
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;
@@ -2007,8 +2086,8 @@ int next_year(struct icalrecur_iterator_impl* impl)
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
@@ -2023,8 +2102,8 @@ int icalrecur_check_rulepart(struct icalrecur_iterator_impl* impl,
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;
@@ -2048,22 +2127,22 @@ int check_contract_restriction(struct icalrecur_iterator_impl* impl,
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;
@@ -2072,11 +2151,9 @@ int check_contracting_rules(struct icalrecur_iterator_impl* impl)
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) &&
@@ -2120,7 +2197,7 @@ struct icaltimetype icalrecur_iterator_next(icalrecur_iterator *itr)
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:{
@@ -2135,7 +2212,7 @@ struct icaltimetype icalrecur_iterator_next(icalrecur_iterator *itr)
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
@@ -2166,16 +2243,15 @@ void icalrecurrencetype_clear(struct icalrecurrencetype *recur)
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)
@@ -2183,9 +2259,9 @@ enum icalrecurrencetype_weekday icalrecurrencetype_day_day_of_week(short day)
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
@@ -2198,7 +2274,7 @@ short icalrecurrencetype_day_position(short day)
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"},
@@ -2238,7 +2314,7 @@ icalrecurrencetype_weekday icalrecur_string_to_weekday(const char* str)
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[] = {
@@ -2276,10 +2352,11 @@ icalrecurrencetype_frequency icalrecur_string_to_freq(const char* str)
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)
@@ -2292,7 +2369,7 @@ int icalrecur_expand_recurrence(char* rule, time_t start,
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