aboutsummaryrefslogtreecommitdiffstats
path: root/libical/src/libical/icalrecur.c
diff options
context:
space:
mode:
Diffstat (limited to 'libical/src/libical/icalrecur.c')
-rw-r--r--libical/src/libical/icalrecur.c1313
1 files changed, 0 insertions, 1313 deletions
diff --git a/libical/src/libical/icalrecur.c b/libical/src/libical/icalrecur.c
deleted file mode 100644
index 6a9bfcd011..0000000000
--- a/libical/src/libical/icalrecur.c
+++ /dev/null
@@ -1,1313 +0,0 @@
-/* -*- Mode: C -*-
- ======================================================================
- FILE: icalrecur.c
- CREATOR: eric 16 May 2000
-
- $Id$
- $Locker$
-
-
- (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of either:
-
- The LGPL as published by the Free Software Foundation, version
- 2.1, available at: http://www.fsf.org/copyleft/lesser.html
-
- Or:
-
- The Mozilla Public License Version 1.0. You may obtain a copy of
- the License at http://www.mozilla.org/MPL/
-
-
- How this code works:
-
- Processing starts when the caller generates a new recurrence
- iterator via icalrecur_iterator_new(). This routine copies the
- recurrence rule into the iterator and extracts things like start and
- end dates. Then, it checks if the rule is legal, using some logic
- from RFC2445 and some logic that probably should be in RFC2445.
-
- Then, icalrecur_iterator_new() re-writes some of the BY*
- arrays. This involves ( via a call to setup_defaults() ) :
-
- 1) For BY rule parts with no data ( ie BYSECOND was not specified )
- copy the corresponding time part from DTSTART into the BY array. (
- So impl->by_ptrs[BY_SECOND] will then have one element if is
- originally had none ) This only happens if the BY* rule part data
- would expand the number of occurrences in the occurrence set. This
- lets the code ignore DTSTART later on and still use it to get the
- time parts that were not specified in any other way.
-
- 2) For the by rule part that are not the same interval as the
- frequency -- for HOURLY anything but BYHOUR, for instance -- copy the
- first data element from the rule part into the first occurrence. For
- example, for "INTERVAL=MONTHLY and BYHOUR=10,30", initialize the
- first time to be returned to have an hour of 10.
-
- Finally, for INTERVAL=YEARLY, the routine expands the rule to get
- all of the days specified in the rule. The code will do this for
- each new year, and this is the first expansion. This is a special
- case for the yearly interval; no other frequency gets expanded this
- way. The yearly interval is the most complex, so some special
- processing is required.
-
- After creating a new iterator, the caller will make successive calls
- to icalrecur_iterator_next() to get the next time specified by the
- rule. The main part of this routine is a switch on the frequency of
- the rule. Each different frequency is handled by a different
- routine.
-
- For example, next_hour handles the case of INTERVAL=HOURLY, and it
- is called by other routines to get the next hour. First, the routine
- tries to get the next minute part of a time with a call to
- next_minute(). If next_minute() returns 1, it has reached the end of
- its data, usually the last element of the BYMINUTE array. Then, if
- there is data in the BYHOUR array, the routine changes the hour to
- the next one in the array. If INTERVAL=HOURLY, the routine advances
- the hour by the interval.
-
- If the routine used the last hour in the BYHOUR array, and the
- INTERVAL=HOURLY, then the routine calls increment_monthday() to set
- the next month day. The increment_* routines may call higher routine
- to increment the month or year also.
-
- The code for INTERVAL=DAILY is handled by next_day(). First, the
- routine tries to get the next hour part of a time with a call to
- next_hour. If next_hour() returns 1, it has reached the end of its
- data, usually the last element of the BYHOUR array. This means that
- next_day() should increment the time to the next day. If FREQUENCY==DAILY,
- the routine increments the day by the interval; otherwise, it
- increments the day by 1.
-
- Next_day() differs from next_hour because it does not use the BYDAY
- array to select an appropriate day. Instead, it returns every day (
- incrementing by 1 if the frequency is not DAILY with INTERVAL!=1)
- Any days that are not specified in an non-empty BYDAY array are
- filtered out later.
-
- Generally, the flow of these routine is for a next_* call a next_*
- routine of a lower interval ( next_day calls next_hour) and then to
- possibly call an increment_* routine of an equal or higher
- interval. ( next_day calls increment_monthday() )
-
- When the call to the original next_* routine returns,
- icalrecur_iterator_next() will check the returned data against other
- BYrule parts to determine if is should be excluded by calling
- check_contracting_rules. Generally, a contracting rule is any with a
- larger time span than the interval. For instance, if
- INTERVAL=DAILY, BYMONTH is a contracting rule part.
-
- Check_contracting_rules() uses check_restriction() to do its
- work. Check_restriction() uses expand_map[] to determine if a rule
- is contracting, and if it is, and if the BY rule part has some data,
- then the routine checks if the value of a component of the time is
- part of the byrule part. For instance, for "INTERVAL=DAILY;
- BYMONTH=6,10", check_restriction() would check that the time value
- given to it has a month of either 6 or 10.
- icalrecurrencetype_test()
-
- Finally, icalrecur_iterator_next() does a few other checks on the
- time value, and if it passes, it returns the time.
-
- ======================================================================*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "icalrecur.h"
-
-#ifdef ICAL_NO_LIBICAL
-#include "icalerror.h"
-#else
-#define icalerror_set_errno(x)
-#define icalerror_check_arg_rv(x,y)
-#endif
-
-#include <stdlib.h> /* for malloc */
-#include <errno.h> /* for errno */
-#include <string.h> /* for strdup */
-#include <assert.h>
-
-#define TEMP_MAX 1024
-
-
-
-
-
-enum byrule {
- NO_CONTRACTION = -1,
- BY_SECOND = 0,
- BY_MINUTE = 1,
- BY_HOUR = 2,
- BY_DAY = 3,
- BY_MONTH_DAY = 4,
- BY_YEAR_DAY = 5,
- BY_WEEK_NO = 6,
- BY_MONTH = 7,
- BY_SET_POS
-};
-
-
-
-struct icalrecur_iterator_impl {
-
- struct icaltimetype dtstart; /* Hack. Make into time_t */
- struct icaltimetype last; /* last time return from _iterator_next*/
- int occurrence_no; /* number of step made on this iterator */
- struct icalrecurrencetype rule;
-
- short days[366];
- short days_index;
-
- enum byrule byrule;
- short by_indices[9];
-
-
- short *by_ptrs[9]; /* Pointers into the by_* array elements of the rule */
-};
-
-int icalrecur_iterator_sizeof_byarray(short* byarray)
-{
- int array_itr;
-
- for(array_itr = 0;
- byarray[array_itr] != ICAL_RECURRENCE_ARRAY_MAX;
- array_itr++){
- }
-
- return array_itr;
-}
-
-enum expand_table {
- UNKNOWN = 0,
- CONTRACT = 1,
- EXPAND =2,
- ILLEGAL=3
-};
-
-/* The split map indicates, for a particular interval, wether a BY_*
- rule part expands the number of instances in the occcurrence set or
- contracts it. 1=> contract, 2=>expand, and 3 means the pairing is
- not allowed. */
-struct expand_split_map_struct
-{
- icalrecurrencetype_frequency frequency;
-
- /* Elements of the 'map' array correspond to the BYxxx rules:
- Second,Minute,Hour,Day,Month Day,Year Day,Week No,Month*/
-
- short map[8];
-};
-
-struct expand_split_map_struct expand_map[] =
-{
- {ICAL_SECONDLY_RECURRENCE,{1,1,1,1,1,1,1,1}},
- {ICAL_MINUTELY_RECURRENCE,{2,1,1,1,1,1,1,1}},
- {ICAL_HOURLY_RECURRENCE, {2,2,1,1,1,1,1,1}},
- {ICAL_DAILY_RECURRENCE, {2,2,2,1,1,1,1,1}},
- {ICAL_WEEKLY_RECURRENCE, {2,2,2,2,3,3,1,1}},
- {ICAL_MONTHLY_RECURRENCE, {2,2,2,2,2,3,3,1}},
- {ICAL_YEARLY_RECURRENCE, {2,2,2,2,2,2,2,2}},
- {ICAL_NO_RECURRENCE, {0,0,0,0,0,0,0,0}}
-
-};
-
-
-
-/* Check that the rule has only the two given interday byrule parts. */
-int icalrecur_two_byrule(struct icalrecur_iterator_impl* impl,
- enum byrule one,enum byrule two)
-{
- short test_array[9];
- enum byrule itr;
- int passes = 0;
-
- memset(test_array,0,9);
-
- test_array[one] = 1;
- test_array[two] = 1;
-
- for(itr = BY_DAY; itr != BY_SET_POS; itr++){
-
- if( (test_array[itr] == 0 &&
- impl->by_ptrs[itr][0] != ICAL_RECURRENCE_ARRAY_MAX
- ) ||
- (test_array[itr] == 1 &&
- impl->by_ptrs[itr][0] == ICAL_RECURRENCE_ARRAY_MAX
- )
- ) {
- /* test failed */
- passes = 0;
- }
- }
-
- return passes;
-
-}
-
-/* Check that the rule has only the one given interdat byrule parts. */
-int icalrecur_one_byrule(struct icalrecur_iterator_impl* impl,enum byrule one)
-{
- int passes = 1;
- enum byrule itr;
-
- for(itr = BY_DAY; itr != BY_SET_POS; itr++){
-
- if ((itr==one && impl->by_ptrs[itr][0] == ICAL_RECURRENCE_ARRAY_MAX) ||
- (itr!=one && impl->by_ptrs[itr][0] != ICAL_RECURRENCE_ARRAY_MAX)) {
- passes = 0;
- }
- }
-
- return passes;
-}
-
-int count_byrules(struct icalrecur_iterator_impl* impl)
-{
- int count = 0;
- enum byrule itr;
-
- for(itr = BY_DAY; itr <= BY_SET_POS; itr++){
- if(impl->by_ptrs[itr][0] != ICAL_RECURRENCE_ARRAY_MAX){
- count++;
- }
- }
-
- return count;
-}
-
-
-void setup_defaults(struct icalrecur_iterator_impl* impl,
- enum byrule byrule, icalrecurrencetype_frequency req,
- short deftime, int *timepart)
-{
-
- icalrecurrencetype_frequency freq;
- freq = impl->rule.freq;
-
- /* Re-write the BY rule arrays with data from the DTSTART time so
- we don't have to explicitly deal with DTSTART */
-
- if(impl->by_ptrs[byrule][0] == ICAL_RECURRENCE_ARRAY_MAX &&
- expand_map[freq].map[byrule] != CONTRACT){
- impl->by_ptrs[byrule][0] = deftime;
- }
-
- /* Initialize the first occurence */
- if( freq != req && expand_map[freq].map[byrule] != CONTRACT){
- *timepart = impl->by_ptrs[byrule][0];
- }
-
-
-}
-
-int expand_year_days(struct icalrecur_iterator_impl* impl,short year);
-
-
-icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule,
- struct icaltimetype dtstart)
-{
- struct icalrecur_iterator_impl* impl;
- icalrecurrencetype_frequency freq;
-
- if ( ( impl = (struct icalrecur_iterator_impl *)
- malloc(sizeof(struct icalrecur_iterator_impl))) == 0) {
- icalerror_set_errno(ICAL_NEWFAILED_ERROR);
- return 0;
- }
-
- memset(impl,0,sizeof(struct icalrecur_iterator_impl));
-
- impl->rule = rule;
- impl->last = dtstart;
- impl->dtstart = dtstart;
- impl->days_index =0;
- impl->occurrence_no = 0;
- freq = impl->rule.freq;
-
- /* Set up convienience pointers to make the code simpler. Allows
- us to iterate through all of the BY* arrays in the rule. */
-
- impl->by_ptrs[BY_MONTH]=impl->rule.by_month;
- impl->by_ptrs[BY_WEEK_NO]=impl->rule.by_week_no;
- impl->by_ptrs[BY_YEAR_DAY]=impl->rule.by_year_day;
- impl->by_ptrs[BY_MONTH_DAY]=impl->rule.by_month_day;
- impl->by_ptrs[BY_DAY]=impl->rule.by_day;
- impl->by_ptrs[BY_HOUR]=impl->rule.by_hour;
- impl->by_ptrs[BY_MINUTE]=impl->rule.by_minute;
- impl->by_ptrs[BY_SECOND]=impl->rule.by_second;
- impl->by_ptrs[BY_SET_POS]=impl->rule.by_set_pos;
-
-
- /* Check if the recurrence rule is legal */
-
- /* If the BYYEARDAY appears, no other date rule part may appear. */
-
- if(icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_MONTH) ||
- icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_WEEK_NO) ||
- icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_MONTH_DAY) ||
- icalrecur_two_byrule(impl,BY_YEAR_DAY,BY_DAY) ){
-
- icalerror_set_errno(ICAL_USAGE_ERROR);
-
- return 0;
- }
-
- /* BYWEEKNO and BYMONTH rule parts may not both appear.*/
-
- if(icalrecur_two_byrule(impl,BY_WEEK_NO,BY_MONTH)){
- icalerror_set_errno(ICAL_USAGE_ERROR);
-
- icalerror_set_errno(ICAL_USAGE_ERROR);
- return 0;
- }
-
- /* BYWEEKNO and BYMONTHDAY rule parts may not both appear.*/
-
- if(icalrecur_two_byrule(impl,BY_WEEK_NO,BY_MONTH_DAY)){
- icalerror_set_errno(ICAL_USAGE_ERROR);
-
- icalerror_set_errno(ICAL_USAGE_ERROR);
- return 0;
- }
-
-
- /*For MONTHLY recurrences (FREQ=MONTHLY) neither BYYEARDAY nor
- BYWEEKNO may appear. */
-
- if(freq == ICAL_MONTHLY_RECURRENCE &&
- ( icalrecur_one_byrule(impl,BY_WEEK_NO) ||
- icalrecur_one_byrule(impl,BY_YEAR_DAY)) ) {
-
- icalerror_set_errno(ICAL_USAGE_ERROR);
- return 0;
- }
-
-
- /*For WEEKLY recurrences (FREQ=WEEKLY) neither BYMONTHDAY nor
- BYYEARDAY may appear. */
-
- if(freq == ICAL_WEEKLY_RECURRENCE &&
- ( icalrecur_one_byrule(impl,BY_MONTH_DAY) ||
- icalrecur_one_byrule(impl,BY_YEAR_DAY)) ) {
-
- icalerror_set_errno(ICAL_USAGE_ERROR);
- return 0;
- }
-
-
- /* Rewrite some of the rules and set up defaults to make later
- processing easier. Primarily, this involves copying an element
- from the start time into the coresponding BY_* array when the
- BY_* array is empty */
-
-
- setup_defaults(impl,BY_SECOND,ICAL_SECONDLY_RECURRENCE,impl->dtstart.second,
- &(impl->last.second));
-
- setup_defaults(impl,BY_MINUTE,ICAL_MINUTELY_RECURRENCE,impl->dtstart.minute,
- &(impl->last.minute));
-
- setup_defaults(impl,BY_HOUR,ICAL_HOURLY_RECURRENCE,impl->dtstart.hour,
- &(impl->last.hour));
-
- setup_defaults(impl,BY_MONTH_DAY,ICAL_DAILY_RECURRENCE,impl->dtstart.day,
- &(impl->last.day));
-
- setup_defaults(impl,BY_MONTH,ICAL_MONTHLY_RECURRENCE,impl->dtstart.month,
- &(impl->last.month));
-
- if(impl->rule.freq == ICAL_WEEKLY_RECURRENCE &&
- impl->by_ptrs[BY_DAY][0] == ICAL_RECURRENCE_ARRAY_MAX){
- impl->by_ptrs[BY_DAY][0] = icaltime_day_of_week(impl->dtstart);
- }
-
-
- if(impl->rule.freq == ICAL_YEARLY_RECURRENCE){
- expand_year_days(impl,impl->dtstart.year);
- }
-
- return impl;
-}
-
-
-void icalrecur_iterator_free(icalrecur_iterator* i)
-{
-
- struct icalrecur_iterator_impl* impl =
- (struct icalrecur_iterator_impl*)i;
-
- icalerror_check_arg_rv((impl!=0),"impl");
-
- free(impl);
-
-}
-
-
-
-
-void increment_year(struct icalrecur_iterator_impl* impl, int inc)
-{
- impl->last.year+=inc;
-}
-
-
-
-
-void increment_month(struct icalrecur_iterator_impl* impl, int inc)
-{
- int years;
-
- impl->last.month+=inc;
-
- /* Months are offset by one */
- impl->last.month--;
-
- years = impl->last.month / 12;
-
- impl->last.month = impl->last.month % 12;
-
- impl->last.month++;
-
- if (years != 0){
- increment_year(impl,years);
- }
-}
-
-void increment_monthday(struct icalrecur_iterator_impl* impl, int inc)
-{
- int i;
-
- for(i=0; i<inc; i++){
-
- short days_in_month =
- icaltime_days_in_month(impl->last.month,impl->last.year);
-
- impl->last.day++;
-
- if (impl->last.day > days_in_month){
- impl->last.day = impl->last.day-days_in_month;
- increment_month(impl,1);
- }
- }
-}
-
-
-void increment_hour(struct icalrecur_iterator_impl* impl, int inc)
-{
- short days;
-
- impl->last.hour+=inc;
-
- days = impl->last.hour / 24;
- impl->last.hour = impl->last.hour % 24;
-
- if (impl->days != 0){
- increment_monthday(impl,days);
- }
-}
-
-void increment_minute(struct icalrecur_iterator_impl* impl, int inc)
-{
- short hours;
-
- impl->last.minute+=inc;
-
- hours = impl->last.minute / 60;
- impl->last.minute = impl->last.minute % 60;
-
- if (hours != 0){
- increment_hour(impl,hours);
- }
-
-}
-
-void increment_second(struct icalrecur_iterator_impl* impl, int inc)
-{
- short minutes;
-
- impl->last.second+=inc;
-
- minutes = impl->last.second / 60;
- impl->last.second = impl->last.second % 60;
-
- if (minutes != 0)
- {
- increment_minute(impl, minutes);
- }
-}
-
-#if 0
-
-#include "ical.h"
-void test_increment()
-{
- struct icalrecur_iterator_impl impl;
-
- impl.last = icaltime_from_string("20000101T000000Z");
-
- printf("Orig: %s\n",icaltime_as_ctime(impl.last));
-
- increment_second(&impl,5);
- printf("+ 5 sec : %s\n",icaltime_as_ctime(impl.last));
-
- increment_second(&impl,355);
- printf("+ 355 sec : %s\n",icaltime_as_ctime(impl.last));
-
- increment_minute(&impl,5);
- printf("+ 5 min : %s\n",icaltime_as_ctime(impl.last));
-
- increment_minute(&impl,360);
- printf("+ 360 min : %s\n",icaltime_as_ctime(impl.last));
- increment_hour(&impl,5);
- printf("+ 5 hours : %s\n",icaltime_as_ctime(impl.last));
- increment_hour(&impl,43);
- printf("+ 43 hours : %s\n",icaltime_as_ctime(impl.last));
- increment_monthday(&impl,3);
- printf("+ 3 days : %s\n",icaltime_as_ctime(impl.last));
- increment_monthday(&impl,600);
- printf("+ 600 days : %s\n",icaltime_as_ctime(impl.last));
-
-}
-
-#endif
-
-short next_second(struct icalrecur_iterator_impl* impl)
-{
-
- short has_by_data = (impl->by_ptrs[BY_SECOND][0]!=ICAL_RECURRENCE_ARRAY_MAX);
- short this_frequency = (impl->rule.freq == ICAL_SECONDLY_RECURRENCE);
-
- short end_of_data = 0;
-
- assert(has_by_data || this_frequency);
-
- if( has_by_data ){
- /* Ignore the frequency and use the byrule data */
-
- impl->by_indices[BY_SECOND]++;
-
- if (impl->by_ptrs[BY_SECOND][impl->by_indices[BY_SECOND]]
- ==ICAL_RECURRENCE_ARRAY_MAX){
- impl->by_indices[BY_SECOND] = 0;
-
- end_of_data = 1;
- }
-
-
- impl->last.second =
- impl->by_ptrs[BY_SECOND][impl->by_indices[BY_SECOND]];
-
-
- } else if( !has_by_data && this_frequency ){
- /* Compute the next value from the last time and the frequency interval*/
- increment_second(impl, impl->rule.interval);
-
- }
-
- /* If we have gone through all of the seconds on the BY list, then we
- need to move to the next minute */
-
- if(has_by_data && end_of_data && this_frequency ){
- increment_minute(impl,1);
- }
-
- return end_of_data;
-
-}
-
-int next_minute(struct icalrecur_iterator_impl* impl)
-{
-
- short has_by_data = (impl->by_ptrs[BY_MINUTE][0]!=ICAL_RECURRENCE_ARRAY_MAX);
- short this_frequency = (impl->rule.freq == ICAL_MINUTELY_RECURRENCE);
-
- short end_of_data = 0;
-
- assert(has_by_data || this_frequency);
-
-
- if (next_second(impl) == 0){
- return 0;
- }
-
- if( has_by_data ){
- /* Ignore the frequency and use the byrule data */
-
- impl->by_indices[BY_MINUTE]++;
-
- if (impl->by_ptrs[BY_MINUTE][impl->by_indices[BY_MINUTE]]
- ==ICAL_RECURRENCE_ARRAY_MAX){
-
- impl->by_indices[BY_MINUTE] = 0;
-
- end_of_data = 1;
- }
-
- impl->last.minute =
- impl->by_ptrs[BY_MINUTE][impl->by_indices[BY_MINUTE]];
-
- } else if( !has_by_data && this_frequency ){
- /* Compute the next value from the last time and the frequency interval*/
- increment_minute(impl,impl->rule.interval);
- }
-
-/* If we have gone through all of the minutes on the BY list, then we
- need to move to the next hour */
-
- if(has_by_data && end_of_data && this_frequency ){
- increment_hour(impl,1);
- }
-
- return end_of_data;
-}
-
-int next_hour(struct icalrecur_iterator_impl* impl)
-{
-
- short has_by_data = (impl->by_ptrs[BY_HOUR][0]!=ICAL_RECURRENCE_ARRAY_MAX);
- short this_frequency = (impl->rule.freq == ICAL_HOURLY_RECURRENCE);
-
- short end_of_data = 0;
-
- assert(has_by_data || this_frequency);
-
- if (next_minute(impl) == 0){
- return 0;
- }
-
- if( has_by_data ){
- /* Ignore the frequency and use the byrule data */
-
- impl->by_indices[BY_HOUR]++;
-
- if (impl->by_ptrs[BY_HOUR][impl->by_indices[BY_HOUR]]
- ==ICAL_RECURRENCE_ARRAY_MAX){
- impl->by_indices[BY_HOUR] = 0;
-
- end_of_data = 1;
- }
-
- impl->last.hour =
- impl->by_ptrs[BY_HOUR][impl->by_indices[BY_HOUR]];
-
- } else if( !has_by_data && this_frequency ){
- /* Compute the next value from the last time and the frequency interval*/
- increment_hour(impl,impl->rule.interval);
-
- }
-
- /* If we have gone through all of the hours on the BY list, then we
- need to move to the next day */
-
- if(has_by_data && end_of_data && this_frequency ){
- increment_monthday(impl,1);
- }
-
- return end_of_data;
-
-}
-
-int next_day(struct icalrecur_iterator_impl* impl)
-{
-
- short has_by_data = (impl->by_ptrs[BY_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX);
- short this_frequency = (impl->rule.freq == ICAL_DAILY_RECURRENCE);
-
- assert(has_by_data || this_frequency);
-
- if (next_hour(impl) == 0){
- return 0;
- }
-
- /* Always increment through the interval, since this routine is not
- called by any other next_* routine, and the days that are
- excluded will be taken care of by restriction filtering */
-
- if(this_frequency){
- increment_monthday(impl,impl->rule.interval);
- } else {
- increment_monthday(impl,1);
- }
-
-
- return 0;
-
-}
-
-/* This routine is only called by next_month and next_year, so it does
- not have a clause for this_frequency */
-int next_monthday(struct icalrecur_iterator_impl* impl)
-{
-
- short has_by_data = (impl->by_ptrs[BY_MONTH_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX);
- short mday;
- short end_of_data = 0;
-
- assert(has_by_data );
-
- if (next_hour(impl) == 0){
- return 0;
- }
-
- impl->by_indices[BY_MONTH_DAY]++;
-
- mday = impl->by_ptrs[BY_MONTH_DAY][impl->by_indices[BY_MONTH_DAY]];
-
- if ( mday ==ICAL_RECURRENCE_ARRAY_MAX){
- impl->by_indices[BY_MONTH_DAY] = 0;
-
- end_of_data = 1;
- }
-
- if (mday > 0){
- impl->last.day = mday;
- } else {
- short days_in_month = icaltime_days_in_month(impl->last.month,
- impl->last.year);
- impl->last.day = days_in_month-mday+1;
- }
-
- if(has_by_data && end_of_data ){
- increment_month(impl,1);
- }
-
- return end_of_data;
-
-}
-
-int next_yearday(struct icalrecur_iterator_impl* impl)
-{
-
- short has_by_data = (impl->by_ptrs[BY_YEAR_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX);
-
- short end_of_data = 0;
-
- assert(has_by_data );
-
- if (next_hour(impl) == 0){
- return 0;
- }
-
- impl->by_indices[BY_YEAR_DAY]++;
-
- if (impl->by_ptrs[BY_YEAR_DAY][impl->by_indices[BY_YEAR_DAY]]
- ==ICAL_RECURRENCE_ARRAY_MAX){
- impl->by_indices[BY_YEAR_DAY] = 0;
-
- end_of_data = 1;
- }
-
- impl->last.day =
- impl->by_ptrs[BY_YEAR_DAY][impl->by_indices[BY_YEAR_DAY]];
-
- if(has_by_data && end_of_data){
- increment_year(impl,1);
- }
-
- return end_of_data;
-
-}
-
-/* This routine is only called by next_week or next_month, so it does
-not have a clause for this_frequency. In both cases, it is certain
-that BY_DAY has data */
-
-int next_weekday(struct icalrecur_iterator_impl* impl)
-{
-
- short end_of_data = 0;
- short start_of_week, dow;
- struct icaltimetype next;
-
- if (next_hour(impl) == 0){
- return 0;
- }
-
- assert( impl->by_ptrs[BY_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX);
-
- impl->by_indices[BY_DAY]++;
-
- if (impl->by_ptrs[BY_DAY][impl->by_indices[BY_DAY]]
- ==ICAL_RECURRENCE_ARRAY_MAX){
- impl->by_indices[BY_DAY] = 0;
-
- end_of_data = 1;
- }
-
- /* HACK. I don't think this handles the Nth day of week rules
- correctly ( "BYDAY=2TU" ) */
- dow = impl->by_ptrs[BY_DAY][impl->by_indices[BY_DAY]];
-
- start_of_week = icaltime_start_doy_of_week(impl->last);
- next = icaltime_from_day_of_year(start_of_week + dow - 1,impl->last.year);
-
- impl->last.day = next.day;
- impl->last.month = next.month;
-
- return end_of_data;
-
-}
-
-int next_month(struct icalrecur_iterator_impl* impl)
-{
-
- short has_by_data = (impl->by_ptrs[BY_MONTH][0]!=ICAL_RECURRENCE_ARRAY_MAX);
- short this_frequency = (impl->rule.freq == ICAL_MONTHLY_RECURRENCE);
-
- short end_of_data = 0;
-
- assert(has_by_data || this_frequency);
-
- /* Week day data overrides monthday data */
- if(impl->by_ptrs[BY_DAY][0]!=ICAL_RECURRENCE_ARRAY_MAX){
- if (next_weekday(impl) == 0){
- return 0;
- }
- } else {
- if (next_monthday(impl) == 0){
- return 0;
- }
- }
-
- if( has_by_data ){
- /* Ignore the frequency and use the byrule data */
-
- impl->by_indices[BY_MONTH]++;
-
- if (impl->by_ptrs[BY_MONTH][impl->by_indices[BY_MONTH]]
- ==ICAL_RECURRENCE_ARRAY_MAX){
- impl->by_indices[BY_MONTH] = 0;
-
- end_of_data = 1;
- }
-
- impl->last.month =
- impl->by_ptrs[BY_MONTH][impl->by_indices[BY_MONTH]];
-
- } else if( !has_by_data && this_frequency ){
- /* Compute the next value from the last time and the frequency interval*/
- increment_month(impl,impl->rule.interval);
-
- }
-
- if(has_by_data && end_of_data && this_frequency ){
- increment_year(impl,1);
- }
- return end_of_data;
-
-}
-
-
-int next_week(struct icalrecur_iterator_impl* impl)
-{
- short has_by_data = (impl->by_ptrs[BY_WEEK_NO][0]!=ICAL_RECURRENCE_ARRAY_MAX);
- short this_frequency = (impl->rule.freq == ICAL_WEEKLY_RECURRENCE);
- short end_of_data = 0;
-
- int sec_in_week = 60*60*24*7;
-
- if (next_weekday(impl) == 0){
- return 0;
- }
-
- if( impl->by_ptrs[BY_WEEK_NO][0]!=ICAL_RECURRENCE_ARRAY_MAX){
- /* Use the Week Number byrule data */
- int week_no;
- time_t tt;
- struct icaltimetype t;
-
- impl->by_indices[BY_WEEK_NO]++;
-
- if (impl->by_ptrs[BY_WEEK_NO][impl->by_indices[BY_WEEK_NO]]
- ==ICAL_RECURRENCE_ARRAY_MAX){
- impl->by_indices[BY_WEEK_NO] = 0;
-
- end_of_data = 1;
- }
-
- t = impl->last;
- t.month=1; /* HACK, should be setting to the date of the first week of year*/
- t.day=1;
-
- week_no = impl->by_ptrs[BY_WEEK_NO][impl->by_indices[BY_WEEK_NO]];
-
- tt = icaltime_as_timet(impl->last);
-
- tt+=sec_in_week*week_no;
-
- impl->last = icaltime_from_timet(tt,impl->last.is_date,impl->last.is_utc);
-
- } else if( !has_by_data && this_frequency ){
- increment_monthday(impl,7*impl->rule.interval);
- }
-
- if(has_by_data && end_of_data && this_frequency ){
- increment_year(impl,1);
- }
-
- return end_of_data;
-
-}
-
-int has_by_data(struct icalrecur_iterator_impl* impl, enum byrule byrule){
-
- return (impl->by_ptrs[byrule][0] != ICAL_RECURRENCE_ARRAY_MAX);
-}
-
-
-/* For INTERVAL=YEARLY, set up the days[] array in the iterator to
- list all of the days of the current year that are specified in this
- rule. */
-
-int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
-{
- int j,k;
- int days_index=0;
- struct icaltimetype t;
-
-
- memset(&t,0,sizeof(t));
- memset(impl->days,ICAL_RECURRENCE_ARRAY_MAX_BYTE,sizeof(impl->days));
-
- if(has_by_data(impl,BY_MONTH) && !has_by_data(impl,BY_MONTH_DAY)){
-
- for(j=0;impl->by_ptrs[BY_MONTH][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){
- struct icaltimetype t;
- short month = impl->by_ptrs[BY_MONTH][j];
- short doy;
-
- t = impl->dtstart;
- t.year = year;
- t.month = month;
-
- doy = icaltime_day_of_year(t);
-
- impl->days[days_index++] = doy;
-
- }
-
-
- }
- else if ( has_by_data(impl,BY_MONTH) && has_by_data(impl,BY_DAY)){
-
- for(j=0;impl->by_ptrs[BY_MONTH][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){
- short month = impl->by_ptrs[BY_MONTH][j];
- short days_in_month = icaltime_days_in_month(month,year);
-
- struct icaltimetype t;
- memset(&t,0,sizeof(struct icaltimetype));
- t.day = 1;
- t.year = year;
- t.month = month;
-
- for(t.day = 1; t.day <=days_in_month; t.day++){
-
- short current_dow = icaltime_day_of_week(t);
-
- for(k=0;impl->by_ptrs[BY_DAY][k]!=ICAL_RECURRENCE_ARRAY_MAX;k++){
-
- enum icalrecurrencetype_weekday dow =
- icalrecurrencetype_day_day_of_week(impl->by_ptrs[BY_DAY][k]);
-
- if(current_dow == dow){
- short doy = icaltime_day_of_year(t);
- /* HACK, incomplete Nth day of week handling */
- impl->days[days_index++] = doy;
-
- }
- }
- }
- }
- } else if (has_by_data(impl,BY_MONTH) && has_by_data(impl,BY_MONTH_DAY)){
-
- for(j=0;impl->by_ptrs[BY_MONTH][j]!=ICAL_RECURRENCE_ARRAY_MAX;j++){
- for(k=0;impl->by_ptrs[BY_MONTH_DAY][k]!=ICAL_RECURRENCE_ARRAY_MAX;k++)
- {
- short month = impl->by_ptrs[BY_MONTH][j];
- short month_day = impl->by_ptrs[BY_MONTH_DAY][k];
- short doy;
-
- t.day = month_day;
- t.month = month;
- t.year = year;
-
- doy = icaltime_day_of_year(t);
-
- impl->days[days_index++] = doy;
-
- }
- }
- } else if (has_by_data(impl,BY_WEEK_NO) && !has_by_data(impl,BY_DAY)){
-
- struct icaltimetype t;
- short dow;
-
- t.day = impl->dtstart.day;
- t.month = impl->dtstart.month;
- t.year = year;
-
- dow = icaltime_day_of_week(t);
-
- } else if (has_by_data(impl,BY_WEEK_NO) && has_by_data(impl,BY_DAY)){
-
- } else if (has_by_data(impl,BY_YEAR_DAY)){
-
- } else if (has_by_data(impl,BY_MONTH_DAY) ){
-
- } else if (has_by_data(impl,BY_DAY)){
-
- } else {
-
- }
-
- return 0;
-}
-
-
-int next_year(struct icalrecur_iterator_impl* impl)
-{
- struct icaltimetype next;
- short end_of_data=0;
-
- if (next_hour(impl) == 0){
- return 0;
- }
-
- impl->days_index++;
-
- if (impl->days[impl->days_index] == ICAL_RECURRENCE_ARRAY_MAX){
- impl->days_index = 0;
- end_of_data = 1;
- }
-
- next = icaltime_from_day_of_year(impl->days[impl->days_index],impl->last.year);
-
- impl->last.day = next.day;
- impl->last.month = next.month;
-
-
- if(end_of_data){
- increment_year(impl,impl->rule.interval);
- expand_year_days(impl,impl->last.year);
- }
-
- return 1;
-}
-
-int check_restriction(struct icalrecur_iterator_impl* impl,
- enum byrule byrule, short v)
-{
- int pass = 0;
- int itr;
- icalrecurrencetype_frequency freq = impl->rule.freq;
-
- if(impl->by_ptrs[byrule][0]!=ICAL_RECURRENCE_ARRAY_MAX &&
- expand_map[freq].map[byrule] == CONTRACT){
- for(itr=0; impl->by_ptrs[byrule][itr]!=ICAL_RECURRENCE_ARRAY_MAX;itr++){
- if(impl->by_ptrs[byrule][itr] == v){
- pass=1;
- break;
- }
- }
-
- return pass;
- } else {
- /* This is not a contracting byrule, or it has no data, so the
- test passes*/
- return 1;
- }
-}
-
-int check_contracting_rules(struct icalrecur_iterator_impl* impl)
-{
- enum byrule;
-
- int day_of_week=0;
- int week_no=0;
- int year_day=0;
-
- if (
- check_restriction(impl,BY_SECOND,impl->last.second) &&
- check_restriction(impl,BY_MINUTE,impl->last.minute) &&
- check_restriction(impl,BY_HOUR,impl->last.hour) &&
- check_restriction(impl,BY_DAY,day_of_week) &&
- check_restriction(impl,BY_WEEK_NO,week_no) &&
- check_restriction(impl,BY_MONTH_DAY,impl->last.day) &&
- check_restriction(impl,BY_MONTH,impl->last.month) &&
- check_restriction(impl,BY_YEAR_DAY,year_day) )
- {
-
- return 1;
- } else {
- return 0;
- }
-}
-
-struct icaltimetype icalrecur_iterator_next(icalrecur_iterator *itr)
-{
- struct icalrecur_iterator_impl* impl =
- (struct icalrecur_iterator_impl*)itr;
-
- if( (impl->rule.count!=0 &&impl->occurrence_no >= impl->rule.count) ||
- (!icaltime_is_null_time(impl->rule.until) &&
- icaltime_compare(impl->last,impl->rule.until) > 0)) {
- return icaltime_null_time();
- }
-
- if(impl->occurrence_no == 0){
- impl->occurrence_no++;
- return impl->last;
- }
-
-
- do {
- switch(impl->rule.freq){
-
- case ICAL_SECONDLY_RECURRENCE: {
- next_second(impl);
- break;
- }
- case ICAL_MINUTELY_RECURRENCE: {
- next_minute(impl);
- break;
- }
- case ICAL_HOURLY_RECURRENCE: {
- next_hour(impl);
- break;
- }
- case ICAL_DAILY_RECURRENCE: {
- next_day(impl);
- break;
- }
- case ICAL_WEEKLY_RECURRENCE: {
- next_week(impl);
- break;
- }
- case ICAL_MONTHLY_RECURRENCE: {
- next_month(impl);
- break;
- }
- case ICAL_YEARLY_RECURRENCE:{
- next_year(impl);
- break;
- }
- default:{
- assert(0); /* HACK, need a better error */
- }
- }
-
- if(impl->last.year >= 2038){
- /* HACK */
- return icaltime_null_time();
- }
-
-
- } while(!check_contracting_rules(impl)
- || icaltime_compare(impl->last,impl->dtstart) < 0);
-
-
- if( !icaltime_is_null_time(impl->rule.until) &&
- icaltime_compare(impl->last,impl->rule.until) > 0) {
- return icaltime_null_time();
- }
-
- impl->occurrence_no++;
-
- return impl->last;
-}
-
-
-/************************** Type Routines **********************/
-
-
-void icalrecurrencetype_clear(struct icalrecurrencetype *recur)
-{
- memset(recur,ICAL_RECURRENCE_ARRAY_MAX_BYTE,
- sizeof(struct icalrecurrencetype));
-
- recur->week_start = ICAL_MONDAY_WEEKDAY;
- recur->freq = ICAL_NO_RECURRENCE;
- recur->interval = 1;
- memset(&(recur->until),0,sizeof(struct icaltimetype));
- recur->count = 0;
-}
-
-/* The 'day' element of icalrecurrencetype_weekday is encoded to allow
-reporesentation of both the day of the week ( Monday, Tueday), but
-also the Nth day of the week ( First tuesday of the month, last
-thursday of the year) These routines decode the day values.
-
-The day's position in the period ( Nth-ness) and the numerical value
-of the day are encoded together as: pos*7 + dow
- */
-
-enum icalrecurrencetype_weekday icalrecurrencetype_day_day_of_week(short day)
-{
- return abs(day)%8;
-}
-
-short icalrecurrencetype_day_position(short day)
-{
- return (day-icalrecurrencetype_day_day_of_week(day))/8;
-}
-
-
-/****************** Enumeration Routines ******************/
-
-struct {icalrecurrencetype_weekday wd; const char * str; }
-wd_map[] = {
- {ICAL_SUNDAY_WEEKDAY,"SU"},
- {ICAL_MONDAY_WEEKDAY,"MO"},
- {ICAL_TUESDAY_WEEKDAY,"TU"},
- {ICAL_WEDNESDAY_WEEKDAY,"WE"},
- {ICAL_THURSDAY_WEEKDAY,"TH"},
- {ICAL_FRIDAY_WEEKDAY,"FR"},
- {ICAL_SATURDAY_WEEKDAY,"SA"},
- {ICAL_NO_WEEKDAY,0}
-};
-
-const char* icalrecur_weekday_to_string(icalrecurrencetype_weekday kind)
-{
- int i;
-
- for (i=0; wd_map[i].wd != ICAL_NO_WEEKDAY; i++) {
- if ( wd_map[i].wd == kind) {
- return wd_map[i].str;
- }
- }
-
- return 0;
-}
-
-
-struct {
- icalrecurrencetype_frequency kind;
- const char* str;
-} freq_map[] = {
- {ICAL_SECONDLY_RECURRENCE,"SECONDLY"},
- {ICAL_MINUTELY_RECURRENCE,"MINUTELY"},
- {ICAL_HOURLY_RECURRENCE,"HOURLY"},
- {ICAL_DAILY_RECURRENCE,"DAILY"},
- {ICAL_WEEKLY_RECURRENCE,"WEEKLY"},
- {ICAL_MONTHLY_RECURRENCE,"MONTHLY"},
- {ICAL_YEARLY_RECURRENCE,"YEARLY"},
- {ICAL_NO_RECURRENCE,0}
-};
-
-const char* icalrecur_recurrence_to_string(icalrecurrencetype_frequency kind)
-{
- int i;
-
- for (i=0; freq_map[i].kind != ICAL_NO_RECURRENCE ; i++) {
- if ( freq_map[i].kind == kind ) {
- return freq_map[i].str;
- }
- }
- return 0;
-}
-
-