From d54f22de6ebd3b8c69468523c0157952bf632eb3 Mon Sep 17 00:00:00 2001 From: Damon Chaplin Date: Thu, 14 Jun 2001 02:50:46 +0000 Subject: merged in some new stuff from libical CVS. (icalrecur_add_byrules): If no 2001-06-13 Damon Chaplin * src/libical/icalrecur.c: merged in some new stuff from libical CVS. (icalrecur_add_byrules): If no sign is given set sign to 1 (i.e. default to positive). (icalrecur_iterator_new): when setting up the year days array, handle the case where a year has no occurrences and we have to skip it. Also initialize the last.day and last.month fields. (expand_by_day): set the last day of the year explicitly rather than adding 1 to year and subtracting 1 from day. It is more efficient, and less prone to bugs. Also rewrote a bit. (expand_year_days): added code to handle BY_MONTH_DAY and BY_DAY + BY_MONTH_DAY, and rewrote code to handle BY_DAY + BY_MONTH. (next_year): handled the case where there are no occurrences in the year. * src/libical/icaltime.c (icaltime_adjust): new function to adjust a time by a number of days/hours/minutes/seconds. (icaltime_day_of_week): rewrote using a single call to mktime(). (icaltime_day_of_year): rewrote using a single call to mktime(). (icaltime_from_day_of_year): rewrote in a simpler way. The old version had a bug in it. * src/libical/icaltime.h (struct icaltimetype): added is_daylight flag, so we can try to distinguish between standard and daylight time when the clocks go back. Though this doesn't always resolve the ambiguity. * src/libical/icalcomponent.c: added some stuff to handle timezone data connected to the calendar component. Unfinished. * src/libical/icalyacc.y: merged in a fix from sourceforge CVS version of libical, so we can handle -ve UTC offsets. * src/libical/Makefile.am (CPPFLAGS): added PACKAGE_DATA_DIR define for finding the VTIMEZONE files. (libical_la_SOURCES): added icalarray.[hc] and icaltimezone.[hc]. (COMBINEDHEADERS): added icalarray.h and icaltimezone.h to the headers to be combined into ical.h. svn path=/trunk/; revision=10220 --- libical/ChangeLog | 40 ++++++++ libical/src/libical/Makefile.am | 10 +- libical/src/libical/icalcomponent.c | 124 ++++++++++++++++++++++++ libical/src/libical/icalrecur.c | 187 +++++++++++++++++++++++++++--------- libical/src/libical/icaltime.c | 151 ++++++++++++++++++++++------- libical/src/libical/icaltime.h | 9 +- libical/src/libical/icalyacc.y | 6 +- 7 files changed, 438 insertions(+), 89 deletions(-) (limited to 'libical') diff --git a/libical/ChangeLog b/libical/ChangeLog index 84aaf6c9f4..7738c42ec0 100644 --- a/libical/ChangeLog +++ b/libical/ChangeLog @@ -1,3 +1,43 @@ +2001-06-13 Damon Chaplin + + * src/libical/icalrecur.c: merged in some new stuff from libical CVS. + (icalrecur_add_byrules): If no sign is given set sign to 1 (i.e. + default to positive). + (icalrecur_iterator_new): when setting up the year days array, handle + the case where a year has no occurrences and we have to skip it. + Also initialize the last.day and last.month fields. + (expand_by_day): set the last day of the year explicitly rather than + adding 1 to year and subtracting 1 from day. It is more efficient, + and less prone to bugs. Also rewrote a bit. + (expand_year_days): added code to handle BY_MONTH_DAY and BY_DAY + + BY_MONTH_DAY, and rewrote code to handle BY_DAY + BY_MONTH. + (next_year): handled the case where there are no occurrences in the + year. + + * src/libical/icaltime.c (icaltime_adjust): new function to adjust a + time by a number of days/hours/minutes/seconds. + (icaltime_day_of_week): rewrote using a single call to mktime(). + (icaltime_day_of_year): rewrote using a single call to mktime(). + (icaltime_from_day_of_year): rewrote in a simpler way. The old version + had a bug in it. + + * src/libical/icaltime.h (struct icaltimetype): added is_daylight + flag, so we can try to distinguish between standard and daylight time + when the clocks go back. Though this doesn't always resolve the + ambiguity. + + * src/libical/icalcomponent.c: added some stuff to handle timezone + data connected to the calendar component. Unfinished. + + * src/libical/icalyacc.y: merged in a fix from sourceforge CVS version + of libical, so we can handle -ve UTC offsets. + + * src/libical/Makefile.am (CPPFLAGS): added PACKAGE_DATA_DIR define + for finding the VTIMEZONE files. + (libical_la_SOURCES): added icalarray.[hc] and icaltimezone.[hc]. + (COMBINEDHEADERS): added icalarray.h and icaltimezone.h to the headers + to be combined into ical.h. + 2001-06-13 Damon Chaplin * src/libical/icaltimezone.[hc]: new files to contain support for diff --git a/libical/src/libical/Makefile.am b/libical/src/libical/Makefile.am index 5c2200c7f0..9e1a6da9ca 100644 --- a/libical/src/libical/Makefile.am +++ b/libical/src/libical/Makefile.am @@ -2,7 +2,7 @@ # FILE: Makefile.am # CREATOR: eric # -# $Id: Makefile.am,v 1.29 2001/05/16 07:16:31 jpr Exp $ +# $Id: Makefile.am,v 1.30 2001/06/14 02:50:46 damon Exp $ # # # (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org @@ -36,6 +36,8 @@ YFLAGS = -d -v -t -pical_yy LFLAGS = -Pical_yy LEX_OUTPUT_ROOT = lex.ical_yy +CPPFLAGS = -DPACKAGE_DATA_DIR=\""$(datadir)/$(PACKAGE)"\" + all: ical.h INCLUDES = \ @@ -48,6 +50,8 @@ libical_la_LDFLAGS = -version-info 0:0:0 libical_la_SOURCES = \ $(BUILT_SOURCES) \ + icalarray.c \ + icalarray.h \ icalattendee.h \ icalattendee.c \ icalcomponent.c \ @@ -73,6 +77,8 @@ libical_la_SOURCES = \ icalrestriction.h \ icaltime.c \ icaltime.h \ + icaltimezone.c \ + icaltimezone.h \ icalduration.h \ icalduration.c \ icalperiod.h \ @@ -114,7 +120,9 @@ COMBINEDHEADERS = \ $(top_srcdir)/src/libical/icalproperty.h \ $(top_srcdir)/src/libical/icalattendee.h \ $(top_srcdir)/src/libical/pvl.h \ + $(top_srcdir)/src/libical/icalarray.h \ $(top_srcdir)/src/libical/icalcomponent.h \ + $(top_srcdir)/src/libical/icaltimezone.h \ $(top_srcdir)/src/libical/icalparser.h \ $(top_srcdir)/src/libical/icalmemory.h \ $(top_srcdir)/src/libical/icalerror.h \ diff --git a/libical/src/libical/icalcomponent.c b/libical/src/libical/icalcomponent.c index c28c972007..ee4ec54f30 100644 --- a/libical/src/libical/icalcomponent.c +++ b/libical/src/libical/icalcomponent.c @@ -33,6 +33,8 @@ #include "icalmemory.h" #include "icalenums.h" #include "icaltime.h" +#include "icalarray.h" +#include "icaltimezone.h" #include "icalduration.h" #include "icalperiod.h" #include "icalparser.h" @@ -55,6 +57,7 @@ struct icalcomponent_impl pvl_list components; pvl_elem component_iterator; icalcomponent* parent; + icalarray* timezones; }; /* icalproperty functions that only components get to use */ @@ -65,6 +68,8 @@ void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args); icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind); int icalcomponent_property_sorter(void *a, void *b); +static void icalcomponent_rename_tzids_callback(icalparameter *param, + void *data); void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args) { @@ -108,6 +113,7 @@ icalcomponent_new_impl (icalcomponent_kind kind) comp->component_iterator = 0; comp->x_name = 0; comp->parent = 0; + comp->timezones = icaltimezone_array_new (); return comp; } @@ -219,6 +225,8 @@ icalcomponent_free (icalcomponent* component) free(c->x_name); } + icalarray_free (c->timezones); + c->kind = ICAL_NO_COMPONENT; c->properties = 0; c->property_iterator = 0; @@ -226,9 +234,11 @@ icalcomponent_free (icalcomponent* component) c->component_iterator = 0; c->x_name = 0; c->id[0] = 'X'; + c->timezones = NULL; free(c); } + } char* @@ -531,6 +541,10 @@ icalcomponent_add_component (icalcomponent* parent, icalcomponent* child) cimpl->parent = parent; pvl_push(impl->components,child); + + /* If the new component is a VTIMEZONE, add it to our array. */ + if (cimpl->kind == ICAL_VTIMEZONE_COMPONENT) + icaltimezone_array_append_from_vtimezone (cimpl->timezones, child); } @@ -546,6 +560,20 @@ icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child) impl = (struct icalcomponent_impl*)parent; cimpl = (struct icalcomponent_impl*)child; + /* If the component is a VTIMEZONE, remove it from our array as well. */ + if (cimpl->kind == ICAL_VTIMEZONE_COMPONENT) { + icaltimezone *zone; + int i; + + for (i = 0; i < impl->timezones->num_elements; i++) { + zone = icalarray_element_at (impl->timezones, i); + if (icaltimezone_get_component (zone) == child) { + icalarray_remove_element_at (impl->timezones, i); + break; + } + } + } + for( itr = pvl_head(impl->components); itr != 0; itr = next_itr) @@ -1485,3 +1513,99 @@ icalcomponent* icalcomponent_new_xdaylight() { return icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT); } + +/* Calls the given function for each TZID parameter found in the component. */ +void icalcomponent_foreach_tzid(icalcomponent* comp, + void (*callback)(icalparameter *param, void *data), + void *callback_data) +{ + icalproperty *prop; + icalproperty_kind kind; + icalparameter *param; + icalcomponent *child; + + /* First rename any TZID parameters used in this component. */ + prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY); + while (prop) { + kind = icalproperty_isa (prop); + + /* These are the only properties that can have a TZID. Note that + COMPLETED, CREATED, DTSTAMP & LASTMODIFIED must be in UTC. */ + if (kind == ICAL_DTSTART_PROPERTY || kind == ICAL_DTEND_PROPERTY + || kind == ICAL_DUE_PROPERTY || kind == ICAL_EXDATE_PROPERTY + || kind == ICAL_RDATE_PROPERTY) { + param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER); + if (param) + (*callback) (param, callback_data); + } + + prop = icalcomponent_get_next_property (comp, ICAL_ANY_PROPERTY); + } + + /* Now recursively rename child components. */ + child = icalcomponent_get_first_component (comp, ICAL_ANY_COMPONENT); + while (child) { + icalcomponent_foreach_tzid (child, callback, callback_data); + child = icalcomponent_get_next_component (comp, ICAL_ANY_COMPONENT); + } +} + + +/* Renames all references to the given TZIDs to a new name. rename_table + contains pairs of strings - a current TZID, and the new TZID to rename it + to. */ +void icalcomponent_rename_tzids(icalcomponent* comp, icalarray* rename_table) +{ + icalcomponent_foreach_tzid (comp, icalcomponent_rename_tzids_callback, + rename_table); +} + + +static void icalcomponent_rename_tzids_callback(icalparameter *param, void *data) +{ + icalarray *rename_table = data; + const char *tzid; + int i; + + tzid = icalparameter_get_tzid (param); + if (!tzid) + return; + + /* Step through the rename table to see if the current TZID matches + any of the ones we want to rename. */ + for (i = 0; i < rename_table->num_elements - 1; i += 2) { + if (!strcmp (tzid, icalarray_element_at (rename_table, i))) + icalparameter_set_tzid (param, icalarray_element_at (rename_table, i + 1)); + } +} + + +/* Returns the icaltimezone from the component corresponding to the given + TZID, or NULL if the component does not have a corresponding VTIMEZONE. */ +icaltimezone* icalcomponent_get_timezone(icalcomponent* comp, const char *tzid) +{ + struct icalcomponent_impl *impl; + icaltimezone *zone; + int lower, upper, middle, cmp; + + impl = (struct icalcomponent_impl*)comp; + + /* Do a simple binary search. */ + lower = middle = 0; + upper = impl->timezones->num_elements; + + while (lower < upper) { + middle = (lower + upper) >> 1; + zone = icalarray_element_at (impl->timezones, middle); + cmp = strcmp (tzid, icaltimezone_get_tzid (zone)); + if (cmp == 0) + return zone; + else if (cmp < 0) + upper = middle; + else + lower = middle + 1; + } + + return NULL; +} + diff --git a/libical/src/libical/icalrecur.c b/libical/src/libical/icalrecur.c index 51fdf63a79..99ebf022f6 100644 --- a/libical/src/libical/icalrecur.c +++ b/libical/src/libical/icalrecur.c @@ -280,6 +280,8 @@ void icalrecur_add_byrules(struct icalrecur_parser *parser, short *array, } else if (*t == '+'){ sign = 1; t++; + } else { + sign = 1; } v = atoi(t) * sign ; @@ -904,7 +906,20 @@ icalrecur_iterator* icalrecur_iterator_new(struct icalrecurrencetype rule, /* For YEARLY rule, begin by setting up the year days array */ if(impl->rule.freq == ICAL_YEARLY_RECURRENCE){ - expand_year_days(impl,impl->last.year); + struct icaltimetype next; + + for (;;) { + expand_year_days(impl,impl->last.year); + if (impl->days[0] != ICAL_RECURRENCE_ARRAY_MAX) + break; + increment_year(impl,impl->rule.interval); + } + + /* Copy the first day into last. */ + next = icaltime_from_day_of_year(impl->days[0], impl->last.year); + + impl->last.day = next.day; + impl->last.month = next.month; } @@ -1618,13 +1633,14 @@ int next_week(struct icalrecur_iterator_impl* impl) } +/* Expand the BYDAY rule part and return a pointer to a newly allocated list of days. */ pvl_list expand_by_day(struct icalrecur_iterator_impl* impl,short year) { /* Try to calculate each of the occurrences. */ int i; pvl_list days_list = pvl_newlist(); - short start_dow, end_dow, end_year_day, start_doy; + short start_dow, end_dow, end_year_day; struct icaltimetype tmp = impl->last; tmp.year= year; @@ -1632,35 +1648,34 @@ pvl_list expand_by_day(struct icalrecur_iterator_impl* impl,short year) tmp.day = 1; tmp.is_date = 1; + /* Find the day that 1st Jan falls on, 1 (Sun) to 7 (Sat). */ start_dow = icaltime_day_of_week(tmp); - start_doy = icaltime_start_doy_of_week(tmp); /* Get the last day of the year*/ - tmp.year++; - tmp = icaltime_normalize(tmp); - tmp.day--; - tmp = icaltime_normalize(tmp); - + tmp.year= year; + tmp.month = 12; + tmp.day = 31; + tmp.is_date = 1; + end_dow = icaltime_day_of_week(tmp); end_year_day = icaltime_day_of_year(tmp); - + for(i = 0; BYDAYPTR[i] != ICAL_RECURRENCE_ARRAY_MAX; i++){ + /* This is 1 (Sun) to 7 (Sat). */ short dow = icalrecurrencetype_day_day_of_week(BYDAYPTR[i]); short pos = icalrecurrencetype_day_position(BYDAYPTR[i]); if(pos == 0){ - /* add all of the days of the year with this day-of-week*/ - int week; - for(week = 0; week < 52 ; week ++){ - short doy = start_doy + (week * 7) + dow-1; - - if(doy > end_year_day){ - break; - } else { - pvl_push(days_list,(void*)(int)doy); - } - } + /* The day was specified without a position -- it is just + a bare day of the week ( BYDAY=SU) so add all of the + days of the year with this day-of-week*/ + int doy, tmp_start_doy; + + tmp_start_doy = ((dow + 7 - start_dow) % 7) + 1; + + for (doy = tmp_start_doy; doy <= end_year_day; doy += 7) + pvl_push(days_list,(void*)(int)doy); } else if ( pos > 0) { int first; @@ -1674,7 +1689,7 @@ pvl_list expand_by_day(struct icalrecur_iterator_impl* impl,short year) pvl_push(days_list,(void*)(first+ (pos-1) * 7)); } else { /* pos < 0 */ - assert(0); + icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); } } @@ -1693,6 +1708,8 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year) struct icaltimetype t; int flags; + t = icaltime_null_time(); + #define HBD(x) has_by_data(impl,x) t.is_date = 1; /* Needed to make day_of_year routines work property */ @@ -1706,12 +1723,12 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year) (HBD(BY_MONTH) ? 1<by_ptrs[BY_MONTH_DAY][k]!=ICAL_RECURRENCE_ARRAY_MAX;k++) + { + short month_day = impl->by_ptrs[BY_MONTH_DAY][k]; + short doy; + + t = impl->dtstart; + t.day = month_day; + t.year = year; + t.is_date = 1; + + doy = icaltime_day_of_year(t); + + impl->days[days_index++] = doy; + + } break; } @@ -1757,7 +1788,6 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year) t.is_date = 1; doy = icaltime_day_of_year(t); - impl->days[days_index++] = doy; } @@ -1779,13 +1809,15 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year) dow = icaltime_day_of_week(t); /* HACK Not finished */ + + icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); break; } case (1<days[days_index++] = day; } + pvl_free(days); + break; } @@ -1811,38 +1845,86 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year) 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); + short first_dow, last_dow, doy_offset; struct icaltimetype t; memset(&t,0,sizeof(struct icaltimetype)); - t.day = 1; t.year = year; t.month = month; + t.day = 1; t.is_date = 1; - for(t.day = 1; t.day <=days_in_month; t.day++){ - - short current_dow = icaltime_day_of_week(t); + first_dow = icaltime_day_of_week(t); + + /* This holds the day offset used to calculate the day of the year + from the month day. Just add the month day to this. */ + doy_offset = icaltime_day_of_year(t) - 1; - 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; - - } + t.day = days_in_month; + last_dow = icaltime_day_of_week(t); + + for(k=0;impl->by_ptrs[BY_DAY][k]!=ICAL_RECURRENCE_ARRAY_MAX;k++){ + short day_coded = impl->by_ptrs[BY_DAY][k]; + enum icalrecurrencetype_weekday dow = + icalrecurrencetype_day_day_of_week(day_coded); + short pos = icalrecurrencetype_day_position(day_coded); + short first_matching_day, last_matching_day, day, month_day; + + /* Calculate the first day in the month with the given weekday, + and the last day. */ + first_matching_day = ((dow + 7 - first_dow) % 7) + 1; + last_matching_day = days_in_month - ((last_dow + 7 - dow) % 7); + + if (pos == 0) { + /* Add all of instances of the weekday within the month. */ + for (day = first_matching_day; day <= days_in_month; day += 7) + impl->days[days_index++] = doy_offset + day; + + } else if (pos > 0) { + /* Add the nth instance of the weekday within the month. */ + month_day = first_matching_day + (pos - 1) * 7; + + if (month_day <= days_in_month) + impl->days[days_index++] = doy_offset + month_day; + + } else { + /* Add the -nth instance of the weekday within the month.*/ + month_day = last_matching_day + (pos + 1) * 7; + + if (month_day > 0) + impl->days[days_index++] = doy_offset + month_day; } - } + } } break; } case (1<days[days_index++] = day; + } + } + + } + + pvl_free(days); + break; } @@ -1873,6 +1955,8 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year) } + pvl_free(days); + break; } @@ -1900,12 +1984,14 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year) } } + + pvl_free(days); break; } case (1<days[++impl->days_index] == ICAL_RECURRENCE_ARRAY_MAX){ impl->days_index = 0; - increment_year(impl,impl->rule.interval); - expand_year_days(impl,impl->last.year); + + for (;;) { + increment_year(impl,impl->rule.interval); + expand_year_days(impl,impl->last.year); + if (impl->days[0] != ICAL_RECURRENCE_ARRAY_MAX) + break; + } } next = icaltime_from_day_of_year(impl->days[impl->days_index],impl->last.year); diff --git a/libical/src/libical/icaltime.c b/libical/src/libical/icaltime.c index d5b228b089..6a3859c094 100644 --- a/libical/src/libical/icaltime.c +++ b/libical/src/libical/icaltime.c @@ -389,17 +389,19 @@ short icaltime_days_in_month(short month,short year) /* 1-> Sunday, 7->Saturday */ short icaltime_day_of_week(struct icaltimetype t){ + struct tm stm; - time_t tt = icaltime_as_timet(t); - struct tm *tm; + stm.tm_year = t.year - 1900; + stm.tm_mon = t.month - 1; + stm.tm_mday = t.day; + stm.tm_hour = 0; + stm.tm_min = 0; + stm.tm_sec = 0; + stm.tm_isdst = -1; - if(t.is_utc == 1){ - tm = gmtime(&tt); - } else { - tm = localtime(&tt); - } + mktime (&stm); - return tm->tm_wday+1; + return stm.tm_wday + 1; } /* Day of the year that the first day of the week (Sunday) is on */ @@ -450,41 +452,49 @@ short icaltime_week_number(struct icaltimetype ictt) short icaltime_day_of_year(struct icaltimetype t){ - time_t tt = icaltime_as_timet(t); - struct tm *stm; + struct tm stm; - if(t.is_utc==1){ - stm = gmtime(&tt); - } else { - stm = localtime(&tt); - } + stm.tm_year = t.year - 1900; + stm.tm_mon = t.month - 1; + stm.tm_mday = t.day; + stm.tm_hour = 0; + stm.tm_min = 0; + stm.tm_sec = 0; + stm.tm_isdst = -1; - return stm->tm_yday+1; - + mktime (&stm); + + return stm.tm_yday + 1; } /* Jan 1 is day #1, not 0 */ struct icaltimetype icaltime_from_day_of_year(short doy, short year) { - struct tm stm; - time_t tt; - char *old_tz = set_tz("UTC"); - - /* Get the time of january 1 of this year*/ - memset(&stm,0,sizeof(struct tm)); - stm.tm_year = year-1900; - stm.tm_mday = 1; - - tt = mktime(&stm); - unset_tz(old_tz); - - - /* Now add in the days */ - - doy--; - tt += doy *60*60*24; + static const short days_in_year[2][13] = + { /* jan feb mar apr may jun jul aug sep oct nov dec */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + struct icaltimetype tt = { 0 }; + int is_leap = 0, month; + + tt.year = year; + if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) + is_leap = 1; + + assert(doy > 0); + assert(doy <= days_in_year[is_leap][12]); + + for (month = 11; month >= 0; month--) { + if (doy > days_in_year[is_leap][month]) { + tt.month = month + 1; + tt.day = doy - days_in_year[is_leap][month]; + return tt; + } + } - return icaltime_from_timet(tt, 1); + /* Shouldn't reach here. */ + assert (0); } struct icaltimetype icaltime_null_time() @@ -564,3 +574,74 @@ struct icaldurationtype icaltime_subtract(struct icaltimetype t1, +/* Adds (or subtracts) a time from a icaltimetype. + NOTE: This function is exactly the same as icaltimezone_adjust_change() + except for the type of the first parameter. */ +void +icaltime_adjust (struct icaltimetype *tt, + int days, + int hours, + int minutes, + int seconds) +{ + int second, minute, hour, day; + int minutes_overflow, hours_overflow, days_overflow; + int days_in_month; + + /* Add on the seconds. */ + second = tt->second + seconds; + tt->second = second % 60; + minutes_overflow = second / 60; + if (tt->second < 0) { + tt->second += 60; + minutes_overflow--; + } + + /* Add on the minutes. */ + minute = tt->minute + minutes + minutes_overflow; + tt->minute = minute % 60; + hours_overflow = minute / 60; + if (tt->minute < 0) { + tt->minute += 60; + hours_overflow--; + } + + /* Add on the hours. */ + hour = tt->hour + hours + hours_overflow; + tt->hour = hour % 24; + days_overflow = hour / 24; + if (tt->hour < 0) { + tt->hour += 24; + days_overflow--; + } + + /* Add on the days. */ + day = tt->day + days + days_overflow; + if (day > 0) { + for (;;) { + days_in_month = icaltime_days_in_month (tt->month, tt->year); + if (day <= days_in_month) + break; + + tt->month++; + if (tt->month >= 13) { + tt->year++; + tt->month = 1; + } + + day -= days_in_month; + } + } else { + while (day <= 0) { + if (tt->month == 1) { + tt->year--; + tt->month = 12; + } else { + tt->month--; + } + + day += icaltime_days_in_month (tt->month, tt->year); + } + } + tt->day = day; +} diff --git a/libical/src/libical/icaltime.h b/libical/src/libical/icaltime.h index 0f0379b76e..afe8fd4df2 100644 --- a/libical/src/libical/icaltime.h +++ b/libical/src/libical/icaltime.h @@ -41,8 +41,8 @@ struct icaltime_span { struct icaltimetype { - int year; - int month; + int year; /* Actual year, e.g. 2001. */ + int month; /* 1 (Jan) to 12 (Dec). */ int day; int hour; int minute; @@ -51,6 +51,8 @@ struct icaltimetype int is_utc; /* 1-> time is in UTC timezone */ int is_date; /* 1 -> interpret this as date. */ + + int is_daylight; /* 1 -> time is in daylight savings time. */ const char* zone; /*Ptr to Olsen placename. Libical does not own mem*/ }; @@ -138,6 +140,9 @@ int icaltime_compare_date_only(struct icaltimetype a, struct icaltimetype b); /* Return the number of days in the given month */ short icaltime_days_in_month(short month,short year); +/* Adds or subtracts a number of days, hours, minutes and seconds. */ +void icaltime_adjust(struct icaltimetype *tt, int days, int hours, + int minutes, int seconds); #endif /* !ICALTIME_H */ diff --git a/libical/src/libical/icalyacc.y b/libical/src/libical/icalyacc.y index 982682d331..c78299fa2a 100644 --- a/libical/src/libical/icalyacc.y +++ b/libical/src/libical/icalyacc.y @@ -6,7 +6,7 @@ DESCRIPTION: - $Id: icalyacc.y,v 1.11 2001/01/23 20:22:33 jpr Exp $ + $Id: icalyacc.y,v 1.12 2001/06/14 02:50:46 damon Exp $ $Locker: $ (C) COPYRIGHT 1999 Eric Busboom @@ -367,12 +367,12 @@ plusminus: '+' { utcsign = 1; } utcoffset_value: plusminus INTNUMBER INTNUMBER { - icalparser_yy_value = icalvalue_new_utcoffset( utcsign * ($2*3600) + ($3*60) ); + icalparser_yy_value = icalvalue_new_utcoffset( utcsign * (($2*3600) + ($3*60)) ); } | plusminus INTNUMBER INTNUMBER INTNUMBER { - icalparser_yy_value = icalvalue_new_utcoffset(utcsign * ($2*3600) + ($3*60) +($4)); + icalparser_yy_value = icalvalue_new_utcoffset(utcsign * (($2*3600) + ($3*60) +($4))); } %% -- cgit v1.2.3