Logo Search packages:      
Sourcecode: libical version File versions  Download package

icalrecur.c File Reference

Detailed Description

Implementation of routines for dealing with recurring time.

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 icalrecur_check_rulepart() to do its work. icalrecur_check_rulepart() 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", icalrecur_check_rulepart() would check that the time value given to it has a month of either 6 or 10.

Finally, icalrecur_iterator_next() does a few other checks on the time value, and if it passes, it returns the time.

A note about the end_of_data flag. The flag indicates that the routine is at the end of its data -- the last BY rule if the routine is using by rules, or the last day of the week/month/year/etc if not.

This flag is usually set early in a next_* routine and returned in the end. The way it is used allows the next_* routine to set the last time back to the first element in a BYxx rule, and then signal to the higer level routine to increment the next higher level. For instance. WITH FREQ=MONTHLY;BYDAY=TU,FR, After next_weekday_by_month runs though both TU and FR, it sets the week day back to TU and sets end_of_data to 1x. This signals next_month to increment the month.


Definition in file icalrecur.c.

#include "icalrecur.h"
#include "icalerror.h"
#include "icalmemory.h"
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <stddef.h>
#include "pvl.h"

Go to the source code of this file.


struct  expand_split_map_struct
struct  icalrecur_iterator_impl
struct  icalrecur_parser


#define BYDAYIDX   impl->by_indices[BY_DAY]
#define BYDAYPTR   impl->by_ptrs[BY_DAY]
#define BYMDIDX   impl->by_indices[BY_MONTH_DAY]
#define BYMDPTR   impl->by_ptrs[BY_MONTH_DAY]
#define BYMONIDX   impl->by_indices[BY_MONTH]
#define BYMONPTR   impl->by_ptrs[BY_MONTH]
#define BYWEEKIDX   impl->by_indices[BY_WEEK_NO]
#define BYWEEKPTR   impl->by_ptrs[BY_WEEK_NO]
#define HBD(x)   has_by_data(impl,x)
#define MAX_TIME_T_YEAR   2037
#define TEMP_MAX   1024


enum  byrule {
  BY_DAY = 3, BY_MONTH_DAY = 4, BY_YEAR_DAY = 5, BY_WEEK_NO = 6,
  BY_MINUTE = 1, BY_HOUR = 2, BY_DAY = 3, BY_MONTH_DAY = 4,
enum  expand_table { UNKNOWN = 0, CONTRACT = 1, EXPAND = 2, ILLEGAL = 3 }


static int check_contract_restriction (icalrecur_iterator *impl, enum byrule byrule, int v)
static int check_contracting_rules (icalrecur_iterator *impl)
static pvl_list expand_by_day (icalrecur_iterator *impl, int year)
static int expand_year_days (icalrecur_iterator *impl, int year)
static int has_by_data (icalrecur_iterator *impl, enum byrule byrule)
void icalrecur_add_bydayrules (struct icalrecur_parser *parser, const char *vals)
void icalrecur_add_byrules (struct icalrecur_parser *parser, short *array, int size, char *vals)
int icalrecur_check_rulepart (icalrecur_iterator *impl, int v, enum byrule byrule)
void icalrecur_clause_name_and_value (struct icalrecur_parser *parser, char **name, char **value)
int icalrecur_expand_recurrence (char *rule, time_t start, int count, time_t *array)
const char * icalrecur_first_clause (struct icalrecur_parser *parser)
const char * icalrecur_freq_to_string (icalrecurrencetype_frequency kind)
void icalrecur_iterator_free (icalrecur_iterator *i)
icalrecur_iteratoricalrecur_iterator_new (struct icalrecurrencetype rule, struct icaltimetype dtstart)
struct icaltimetype icalrecur_iterator_next (icalrecur_iterator *impl)
int icalrecur_iterator_sizeof_byarray (short *byarray)
const char * icalrecur_next_clause (struct icalrecur_parser *parser)
static int icalrecur_one_byrule (icalrecur_iterator *impl, enum byrule one)
icalrecurrencetype_frequency icalrecur_string_to_freq (const char *str)
icalrecurrencetype_weekday icalrecur_string_to_weekday (const char *str)
static int icalrecur_two_byrule (icalrecur_iterator *impl, enum byrule one, enum byrule two)
const char * icalrecur_weekday_to_string (icalrecurrencetype_weekday kind)
char * icalrecurrencetype_as_string (struct icalrecurrencetype *recur)
void icalrecurrencetype_clear (struct icalrecurrencetype *recur)
enum icalrecurrencetype_weekday icalrecurrencetype_day_day_of_week (short day)
int icalrecurrencetype_day_position (short day)
struct icalrecurrencetype icalrecurrencetype_from_string (const char *str)
static void increment_hour (icalrecur_iterator *impl, int inc)
static void increment_minute (icalrecur_iterator *impl, int inc)
static void increment_month (icalrecur_iterator *impl)
static void increment_monthday (icalrecur_iterator *impl, int inc)
static void increment_second (icalrecur_iterator *impl, int inc)
static void increment_year (icalrecur_iterator *impl, int inc)
static int is_day_in_byday (icalrecur_iterator *impl, struct icaltimetype tt)
static int next_day (icalrecur_iterator *impl)
static int next_hour (icalrecur_iterator *impl)
static int next_minute (icalrecur_iterator *impl)
static int next_month (icalrecur_iterator *impl)
static int next_second (icalrecur_iterator *impl)
static int next_week (icalrecur_iterator *impl)
static int next_weekday_by_week (icalrecur_iterator *impl)
static int next_year (icalrecur_iterator *impl)
static int nth_weekday (int dow, int pos, struct icaltimetype t)
void print_date_to_string (char *str, struct icaltimetype *data)
void print_datetime_to_string (char *str, struct icaltimetype *data)
static void setup_defaults (icalrecur_iterator *impl, enum byrule byrule, icalrecurrencetype_frequency req, int deftime, int *timepart)
static void sort_bydayrules (struct icalrecur_parser *parser)


static struct
expand_map []
struct {
   icalrecurrencetype_frequency   kind
   const char *   str
freq_map []
struct {
   int   limit
   size_t   offset
   const char *   str
recurmap []
struct {
   const char *   str
   icalrecurrencetype_weekday   wd
wd_map []

Generated by  Doxygen 1.6.0   Back to index