From b1d0fa6651480b281a59994d3864d94947f6d43e Mon Sep 17 00:00:00 2001 From: helge Date: Mon, 19 Sep 2005 21:44:06 +0000 Subject: [PATCH] added ievalrrule tool minor improvs in iCalRecurrenceRule git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1116 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-ical/NGiCal/ChangeLog | 5 + sope-ical/NGiCal/Version | 2 +- sope-ical/NGiCal/iCalRecurrenceRule.h | 21 ++- sope-ical/NGiCal/iCalRecurrenceRule.m | 193 ++++++++++++------------- sope-ical/NGiCal/tests/README | 2 - sope-ical/samples/ChangeLog | 4 + sope-ical/samples/GNUmakefile | 3 +- sope-ical/samples/GNUmakefile.preamble | 3 + sope-ical/samples/ievalrrule.m | 79 ++++++++++ sope-ical/samples/vcfparsetest.m | 5 +- 10 files changed, 202 insertions(+), 115 deletions(-) create mode 100644 sope-ical/samples/ievalrrule.m diff --git a/sope-ical/NGiCal/ChangeLog b/sope-ical/NGiCal/ChangeLog index c8502f93..ebe1c60d 100644 --- a/sope-ical/NGiCal/ChangeLog +++ b/sope-ical/NGiCal/ChangeLog @@ -1,3 +1,8 @@ +2005-09-19 Helge Hess + + * iCalRecurrenceRule.m: minor code improvements, more tolerant on + invalid iCal rrule input (v4.5.61) + 2005-08-16 Helge Hess * GNUmakefile, GNUmakefile.preamble: added OSX framework compilation diff --git a/sope-ical/NGiCal/Version b/sope-ical/NGiCal/Version index a5b5ba42..1b755532 100644 --- a/sope-ical/NGiCal/Version +++ b/sope-ical/NGiCal/Version @@ -2,7 +2,7 @@ MAJOR_VERSION=4 MINOR_VERSION=5 -SUBMINOR_VERSION:=60 +SUBMINOR_VERSION:=61 # v4.5.40 requires NGExtensions v4.5.145 # v4.5.37 requires NGExtensions v4.5.140 diff --git a/sope-ical/NGiCal/iCalRecurrenceRule.h b/sope-ical/NGiCal/iCalRecurrenceRule.h index 96e77e94..9cc99901 100644 --- a/sope-ical/NGiCal/iCalRecurrenceRule.h +++ b/sope-ical/NGiCal/iCalRecurrenceRule.h @@ -25,13 +25,13 @@ #import /* - iCalRecurrenceRule + iCalRecurrenceRule - Encapsulates a (probably complex) recurrence rule by offering - a high level API. + Encapsulates a (probably complex) recurrence rule by offering + a high level API. - NOTE: as of now, only a very limited subset of RFC2445 is implemented. - Please see the unit tests for what is covered. + NOTE: as of now, only a very limited subset of RFC2445 is implemented. + Please see the unit tests for what is covered. */ typedef enum { @@ -71,26 +71,35 @@ typedef enum { } + (id)recurrenceRuleWithICalRepresentation:(NSString *)_iCalRep; +- (id)initWithString:(NSString *)_str; + +/* accessors */ - (void)setFrequency:(iCalRecurrenceFrequency)_frequency; - (iCalRecurrenceFrequency)frequency; + - (void)setRepeatInterval:(int)_repeatInterval; - (int)repeatInterval; + - (void)setWeekStart:(iCalWeekDay)_weekStart; - (iCalWeekDay)weekStart; + - (void)setByDayMask:(unsigned)_mask; - (unsigned)byDayMask; /* count and untilDate are mutually exclusive */ + - (void)setRepeatCount:(unsigned)_repeatCount; - (unsigned)repeatCount; + - (void)setUntilDate:(NSCalendarDate *)_untilDate; - (NSCalendarDate *)untilDate; - (BOOL)isInfinite; /* parse complete iCal RRULE */ -- (void)setRrule:(NSString *)_rrule; + +- (void)setRrule:(NSString *)_rrule; // TODO: weird name? (better: RRule?) - (NSString *)iCalRepresentation; diff --git a/sope-ical/NGiCal/iCalRecurrenceRule.m b/sope-ical/NGiCal/iCalRecurrenceRule.m index a502ed9d..55a1a1db 100644 --- a/sope-ical/NGiCal/iCalRecurrenceRule.m +++ b/sope-ical/NGiCal/iCalRecurrenceRule.m @@ -24,23 +24,25 @@ #include "common.h" /* - freq = rrFreq; - until = rrUntil; - count = rrCount; - interval = rrInterval; - bysecond = rrBySecondList; - byminute = rrByMinuteList; - byhour = rrByHourList; - byday = rrByDayList; - bymonthday = rrByMonthDayList; - byyearday = rrByYearDayList; - byweekno = rrByWeekNumberList; - bymonth = rrByMonthList; - bysetpos = rrBySetPosList; - wkst = rrWeekStart; - */ + freq = rrFreq; + until = rrUntil; + count = rrCount; + interval = rrInterval; + bysecond = rrBySecondList; + byminute = rrByMinuteList; + byhour = rrByHourList; + byday = rrByDayList; + bymonthday = rrByMonthDayList; + byyearday = rrByYearDayList; + byweekno = rrByWeekNumberList; + bymonth = rrByMonthList; + bysetpos = rrBySetPosList; + wkst = rrWeekStart; +*/ +// TODO: private API in the header file?! @interface iCalRecurrenceRule (PrivateAPI) + - (iCalWeekDay)weekDayFromICalRepresentation:(NSString *)_day; - (NSString *)iCalRepresentationForWeekDay:(iCalWeekDay)_weekDay; - (NSString *)freq; @@ -48,35 +50,31 @@ - (NSString *)byDayList; - (void)_processRule; -- (void)setRrule:(NSString *)_rrule; +- (void)setRrule:(NSString *)_rrule; // TODO: weird name? + @end @implementation iCalRecurrenceRule -+ (void)initialize { - static BOOL didInit = NO; - - if (didInit) return; - didInit = YES; -} - + (id)recurrenceRuleWithICalRepresentation:(NSString *)_iCalRep { - iCalRecurrenceRule *r; - - r = [[[self alloc] init] autorelease]; - [r setRrule:_iCalRep]; - return r; + return [[[self alloc] initWithString:_iCalRep] autorelease]; } -- (id)init { - self = [super init]; - if (self) { +- (id)init { /* designated initializer */ + if ((self = [super init]) != nil) { self->byDay.weekStart = iCalWeekDayMonday; self->interval = 1; } return self; } +- (id)initWithString:(NSString *)_str { + if ((self = [self init]) != nil) { + [self setRrule:_str]; + } + return self; +} + - (void)dealloc { [self->untilDate release]; [self->rrule release]; @@ -84,7 +82,7 @@ } -/* Accessors */ +/* accessors */ - (void)setFrequency:(iCalRecurrenceFrequency)_frequency { self->frequency = _frequency; @@ -133,67 +131,57 @@ } -/* Private */ +/* private */ - (iCalWeekDay)weekDayFromICalRepresentation:(NSString *)_day { - _day = [_day uppercaseString]; - if ([_day isEqualToString:@"MO"]) - return iCalWeekDayMonday; - else if ([_day isEqualToString:@"TU"]) - return iCalWeekDayTuesday; - else if ([_day isEqualToString:@"WE"]) - return iCalWeekDayWednesday; - else if ([_day isEqualToString:@"TH"]) - return iCalWeekDayThursday; - else if ([_day isEqualToString:@"FR"]) - return iCalWeekDayFriday; - else if ([_day isEqualToString:@"SA"]) - return iCalWeekDaySaturday; - else if ([_day isEqualToString:@"SU"]) - return iCalWeekDaySunday; - else - [NSException raise:NSGenericException - format:@"Incorrect weekDay '%@' specified!", _day]; + if ([_day length] > 1) { + /* be tolerant */ + unichar c0, c1; + + c0 = [_day characterAtIndex:0]; + if (c0 == 'm' || c0 == 'M') return iCalWeekDayMonday; + if (c0 == 'w' || c0 == 'W') return iCalWeekDayWednesday; + if (c0 == 'f' || c0 == 'F') return iCalWeekDayFriday; + + c1 = [_day characterAtIndex:1]; + if (c0 == 't' || c0 == 't') { + if (c1 == 'u' || c1 == 'U') return iCalWeekDayTuesday; + if (c1 == 'h' || c1 == 'H') return iCalWeekDayThursday; + } + if (c0 == 's' || c0 == 'S') { + if (c1 == 'a' || c1 == 'A') return iCalWeekDaySaturday; + if (c1 == 'u' || c1 == 'U') return iCalWeekDaySunday; + } + } + + // TODO: do not raise but rather return an error value? + [NSException raise:NSGenericException + format:@"Incorrect weekDay '%@' specified!", _day]; return iCalWeekDayMonday; /* keep compiler happy */ } - (NSString *)iCalRepresentationForWeekDay:(iCalWeekDay)_weekDay { switch (_weekDay) { - case iCalWeekDayMonday: - return @"MO"; - case iCalWeekDayTuesday: - return @"TU"; - case iCalWeekDayWednesday: - return @"WE"; - case iCalWeekDayThursday: - return @"TH"; - case iCalWeekDayFriday: - return @"FR"; - case iCalWeekDaySaturday: - return @"SA"; - case iCalWeekDaySunday: - return @"SU"; - default: - return @"MO"; + case iCalWeekDayMonday: return @"MO"; + case iCalWeekDayTuesday: return @"TU"; + case iCalWeekDayWednesday: return @"WE"; + case iCalWeekDayThursday: return @"TH"; + case iCalWeekDayFriday: return @"FR"; + case iCalWeekDaySaturday: return @"SA"; + case iCalWeekDaySunday: return @"SU"; + default: return @"MO"; // TODO: return error? } } - (NSString *)freq { switch (self->frequency) { - case iCalRecurrenceFrequenceWeekly: - return @"WEEKLY"; - case iCalRecurrenceFrequenceMonthly: - return @"MONTHLY"; - case iCalRecurrenceFrequenceDaily: - return @"DAILY"; - case iCalRecurrenceFrequenceYearly: - return @"YEARLY"; - case iCalRecurrenceFrequenceHourly: - return @"HOURLY"; - case iCalRecurrenceFrequenceMinutely: - return @"MINUTELY"; - case iCalRecurrenceFrequenceSecondly: - return @"SECONDLY"; + case iCalRecurrenceFrequenceWeekly: return @"WEEKLY"; + case iCalRecurrenceFrequenceMonthly: return @"MONTHLY"; + case iCalRecurrenceFrequenceDaily: return @"DAILY"; + case iCalRecurrenceFrequenceYearly: return @"YEARLY"; + case iCalRecurrenceFrequenceHourly: return @"HOURLY"; + case iCalRecurrenceFrequenceMinutely: return @"MINUTELY"; + case iCalRecurrenceFrequenceSecondly: return @"SECONDLY"; default: return @"UNDEFINED?"; } @@ -204,15 +192,15 @@ } /* - TODO: - Each BYDAY value can also be preceded by a positive (+n) or negative - (-n) integer. If present, this indicates the nth occurrence of the - specific day within the MONTHLY or YEARLY RRULE. For example, within - a MONTHLY rule, +1MO (or simply 1MO) represents the first Monday - within the month, whereas -1MO represents the last Monday of the - month. If an integer modifier is not present, it means all days of - this type within the specified frequency. For example, within a - MONTHLY rule, MO represents all Mondays within the month. + TODO: + Each BYDAY value can also be preceded by a positive (+n) or negative + (-n) integer. If present, this indicates the nth occurrence of the + specific day within the MONTHLY or YEARLY RRULE. For example, within + a MONTHLY rule, +1MO (or simply 1MO) represents the first Monday + within the month, whereas -1MO represents the last Monday of the + month. If an integer modifier is not present, it means all days of + this type within the specified frequency. For example, within a + MONTHLY rule, MO represents all Mondays within the month. */ - (NSString *)byDayList { NSMutableString *s; @@ -223,6 +211,7 @@ needsComma = NO; mask = self->byDay.mask; day = iCalWeekDayMonday; + for (i = 0; i < 7; i++) { if (mask & day) { if (needsComma) @@ -238,7 +227,7 @@ /* Rule */ - (void)setRrule:(NSString *)_rrule { - ASSIGN(self->rrule, _rrule); + ASSIGNCOPY(self->rrule, _rrule); [self _processRule]; } @@ -249,14 +238,13 @@ unsigned i, count; props = [self->rrule componentsSeparatedByString:@";"]; - count = [props count]; - for (i = 0; i < count; i++) { + for (i = 0, count = [props count]; i < count; i++) { NSString *prop, *key, *value; NSRange r; prop = [props objectAtIndex:i]; r = [prop rangeOfString:@"="]; - if (r.length) { + if (r.length > 0) { key = [prop substringToIndex:r.location]; value = [prop substringFromIndex:NSMaxRange(r)]; } @@ -287,9 +275,10 @@ self->frequency = iCalRecurrenceFrequenceMinutely; else if ([_freq isEqualToString:@"SECONDLY"]) self->frequency = iCalRecurrenceFrequenceSecondly; - else + else { [NSException raise:NSGenericException format:@"Incorrect frequency '%@' specified!", _freq]; + } } - (void)setInterval:(NSString *)_interval { @@ -315,8 +304,7 @@ self->byDay.mask = 0; days = [_byDayList componentsSeparatedByString:@","]; - count = [days count]; - for (i = 0; i < count; i++) { + for (i = 0, count = [days count]; i < count; i++) { NSString *iCalDay; iCalWeekDay day; @@ -333,17 +321,19 @@ } -/* Description */ +/* description */ - (NSString *)iCalRepresentation { NSMutableString *s; s = [NSMutableString stringWithCapacity:80]; + [s appendString:@"FREQ="]; [s appendString:[self freq]]; - if ([self repeatInterval] != 1) { + + if ([self repeatInterval] != 1) [s appendFormat:@";INTERVAL=%d", [self repeatInterval]]; - } + if (![self isInfinite]) { if ([self repeatCount] > 0) { [s appendFormat:@";COUNT=%d", [self repeatCount]]; @@ -364,5 +354,4 @@ return s; } - -@end +@end /* iCalRecurrenceRule */ diff --git a/sope-ical/NGiCal/tests/README b/sope-ical/NGiCal/tests/README index cff29bb3..5541041c 100644 --- a/sope-ical/NGiCal/tests/README +++ b/sope-ical/NGiCal/tests/README @@ -1,5 +1,3 @@ -$Id$ - This folder contains unit tests for the NGiCal project. It uses SEN:TE's OCUnit project which can be found at diff --git a/sope-ical/samples/ChangeLog b/sope-ical/samples/ChangeLog index 1ca2105e..611bc48d 100644 --- a/sope-ical/samples/ChangeLog +++ b/sope-ical/samples/ChangeLog @@ -1,3 +1,7 @@ +2005-09-19 Helge Hess + + * ievalrrule.m: started tool to evaluate iCal rrules on the shell + 2005-08-16 Helge Hess * link tools against OSX frameworks if configured so diff --git a/sope-ical/samples/GNUmakefile b/sope-ical/samples/GNUmakefile index 61b8e8a5..afeb8f0c 100644 --- a/sope-ical/samples/GNUmakefile +++ b/sope-ical/samples/GNUmakefile @@ -3,12 +3,13 @@ -include ../../config.make include $(GNUSTEP_MAKEFILES)/common.make -TOOL_NAME = icalparsetest icalds vcf2xml vcfparsetest +TOOL_NAME = icalparsetest icalds vcf2xml vcfparsetest ievalrrule icalparsetest_OBJC_FILES = icalparsetest.m icalds_OBJC_FILES = icalds.m vcf2xml_OBJC_FILES = vcf2xml.m vcfparsetest_OBJC_FILES = vcfparsetest.m +ievalrrule_OBJC_FILES = ievalrrule.m -include GNUmakefile.preamble include $(GNUSTEP_MAKEFILES)/tool.make diff --git a/sope-ical/samples/GNUmakefile.preamble b/sope-ical/samples/GNUmakefile.preamble index ce9af8e8..2c704e39 100644 --- a/sope-ical/samples/GNUmakefile.preamble +++ b/sope-ical/samples/GNUmakefile.preamble @@ -16,6 +16,7 @@ icalparsetest_PCH_FILE = common.h icalds_PCH_FILE = common.h vcf2xml_PCH_FILE = common.h vcfparsetest_PCH_FILE = common.h +ievalrrule_PCH_FILE = common.h # dependencies @@ -24,6 +25,7 @@ ifneq ($(frameworks),yes) icalparsetest_TOOL_LIBS += -lNGiCal icalds_TOOL_LIBS += -lNGiCal vcfparsetest_TOOL_LIBS += -lNGiCal +ievalrrule_TOOL_LIBS += -lNGiCal ADDITIONAL_TOOL_LIBS += \ -lNGStreams -lNGExtensions -lEOControl \ @@ -32,6 +34,7 @@ else icalparsetest_TOOL_LIBS += -framework NGiCal icalds_TOOL_LIBS += -framework NGiCal vcfparsetest_TOOL_LIBS += -framework NGiCal +ievalrrule_TOOL_LIBS += -framework NGiCal ADDITIONAL_TOOL_LIBS += \ -framework NGStreams -framework NGExtensions -framework EOControl \ diff --git a/sope-ical/samples/ievalrrule.m b/sope-ical/samples/ievalrrule.m new file mode 100644 index 00000000..1ce1111d --- /dev/null +++ b/sope-ical/samples/ievalrrule.m @@ -0,0 +1,79 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + SOPE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include +#include "common.h" + +static int usage(NSArray *args) { + fprintf(stderr, + "usage: %s \n" + "\n" + "sample:\n" + " %s 'FREQ=MONTHLY;BYDAY=2TU' 20050901 20060301\n", + [[args objectAtIndex:0] cString], + [[args objectAtIndex:0] cString]); + return 1; +} + +static int runIt(NSArray *args) { + iCalRecurrenceRule *rrule; + NSCalendarDate *from, *to; + NSString *pattern; + NSString *s; + + if ([args count] < 4) + return usage(args); + + pattern = [args objectAtIndex:1]; + s = [[args objectAtIndex:2] stringByAppendingString:@" 00:00"]; + from = [NSCalendarDate dateWithString:s calendarFormat:@"%Y%m%d %H:%M"]; + s = [[args objectAtIndex:3] stringByAppendingString:@" 23:59"]; + to = [NSCalendarDate dateWithString:s calendarFormat:@"%Y%m%d %H:%M"]; + + if (from == nil || to == nil || ![pattern isNotEmpty]) + return usage(args); + + if ((rrule = [[iCalRecurrenceRule alloc] initWithString:pattern]) == nil) { + usage(args); + fprintf(stderr, "error: could not parse reccurence rule: '%s'\n", + [pattern cString]); + return 2; + } + + NSLog(@"from: %@ to: %@", from, to); + NSLog(@"rrule: %@", rrule); + + return 0; +} + +int main(int argc, char **argv, char **env) { + NSAutoreleasePool *pool; + int rc; + + pool = [[NSAutoreleasePool alloc] init]; +#if LIB_FOUNDATION_LIBRARY + [NSProcessInfo initializeWithArguments:argv count:argc environment:env]; +#endif + + rc = runIt([[NSProcessInfo processInfo] argumentsWithoutDefaults]); + [pool release]; + return rc; +} diff --git a/sope-ical/samples/vcfparsetest.m b/sope-ical/samples/vcfparsetest.m index 26289af2..54af86b4 100644 --- a/sope-ical/samples/vcfparsetest.m +++ b/sope-ical/samples/vcfparsetest.m @@ -103,13 +103,12 @@ int main(int argc, char **argv, char **env) { vcsparsetest *tool; int rc; + pool = [[NSAutoreleasePool alloc] init]; #if LIB_FOUNDATION_LIBRARY [NSProcessInfo initializeWithArguments:argv count:argc environment:env]; #endif - pool = [[NSAutoreleasePool alloc] init]; - - if ((tool = [[vcsparsetest alloc] init])) { + if ((tool = [[vcsparsetest alloc] init]) != nil) { NS_DURING rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]]; NS_HANDLER -- 2.39.5