an iCal processing library
Revision 2:1f5dbc624b95, committed 2014-05-17
- Comitter:
- WiredHome
- Date:
- Sat May 17 19:54:51 2014 +0000
- Parent:
- 1:db274b9e40cc
- Child:
- 3:fc5cdc930896
- Commit message:
- Working to improve the recurring event parsing
Changed in this revision
iCal.cpp | Show annotated file Show diff for this revision Revisions of this file |
--- a/iCal.cpp Sun Apr 20 16:34:18 2014 +0000 +++ b/iCal.cpp Sat May 17 19:54:51 2014 +0000 @@ -1,9 +1,13 @@ - +// +// TODO +// Repeat parsing is quite weak right now. It handles repeating days w/in a week +// (e.g. repeat weekly, on Mon, Tue, Thu) +// #include "iCal.h" #include <algorithm> -//#define DEBUG "iCal" +#define DEBUG "iCal" #include <cstdio> #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) #define DBG(x, ...) std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); @@ -70,7 +74,7 @@ { time_t tStamp; struct tm t; - //INFO("ParseDateStamp(..., %s)\r\n", string); + INFO("ParseDateStamp(%s,%d)\r\n", string, tzoSec); t.tm_year = AtoIxN(string, 4) - 1900; t.tm_mon = AtoIxN(string+4, 2) - 1; t.tm_mday = AtoIxN(string+6, 2); @@ -78,8 +82,10 @@ t.tm_min = AtoIxN(string+11, 2); t.tm_sec = AtoIxN(string+13, 2); tStamp = mktime(&t); - if (string[strlen(string)-1] == 'Z') + if (string[strlen(string)-1] == 'Z') { + INFO("Applying tzoSec %d", tzoSec); tStamp = tStamp + tzoSec; + } return tStamp; //int tm_sec //seconds after the minute – [0, 60][@1] (public member object) //int tm_min //minutes after the hour – [0, 59] (public member object) @@ -96,7 +102,7 @@ { static char temp[4][80]; static int i = 0; - + i &= 3; strcpy(temp[i], ctime(&t)); temp[i][strlen(temp[i])-1] = '\0'; @@ -107,7 +113,7 @@ void ShowEventInfo(Event_T & Event) { char temp[80]; - + INFO("*** Summary: %s", Event.Summary); strcpy(temp, ctime(&Event.Start)); temp[strlen(temp)-1] = '\0'; @@ -172,16 +178,45 @@ time_t NextInterval(int repeatFreq, int interval) { - time_t secperday = 60*60*24; - const int repeatFactor[] = {1, 7, 30, 365}; + const time_t secperday = 60*60*24; + const int repeatFactor[] = {0, 1, 7, 30, 365}; INFO("freq %d, interval %d", repeatFreq, interval); return repeatFactor[repeatFreq-1] * interval * secperday; } + +// start1,end1 is the time range representing the visible grid +// start2,end2 is the time range of the event being tested +// Event is also the event being tested and permits testing the repeat information. +// +// If the event repeat pattern intersects with the display pattern, indicate this as "true" +// +bool RepeatMaskIntersects(time_t * start1, time_t * end1, time_t * start2, time_t * end2, Event_T & Event) +{ + bool intersects = false; + + if (Event.RepeatFreq == rptfWeekly) { + struct tm * timeinfo; + timeinfo = localtime(start1); + uint8_t daymask = Event.RepeatDays; + // now, check the tm_wday (0=Sunday, 1=Monday, ...) and see if we intersect with the event time + uint8_t testmask = 1 << timeinfo->tm_wday; + //INFO("Mask: Event mask: %02X, test mask: %02X", daymask, testmask); + if (daymask & testmask) + intersects = true; + else + intersects = false; + //INFO(" intersects: %02X", daymask & testmask); + return intersects; + } + //INFO("Mask: no handler, returning true"); + return true; +} + bool RepeatIntersects(time_t * start1, time_t * end1, time_t * start2, time_t * end2, Event_T & Event) { if (Event.RepeatFreq) { - INFO("%s", Event.Summary); + INFO("Summary: %s", Event.Summary); INFO("** 1: (%s, %s)", FormatCTime(*start1), FormatCTime(*end1)); INFO(" 2: (%s, %s)", FormatCTime(*start2), FormatCTime(*end2)); if (TimeIntersects(start1, end1, start2, end2)) { @@ -194,10 +229,13 @@ INFO("** 1: (%s, %s)", FormatCTime(*start1), FormatCTime(*end1)); INFO("until (%24s, %s)", " ", FormatCTime(Event.Until)); INFO(" 2: (%s, %s)", FormatCTime(*start2), FormatCTime(*end2)); + if (!RepeatMaskIntersects(start1, end1, start2, end2, Event)) { + continue; // we're not on a repeat cycle (e.g. wrong day of the week) + } if (TimeIntersects(start1, end1, start2, end2)) { return true; } - } while (*start1 < *end2 && *start1 < Event.Until); + } while (*start1 < *end2 && *start1 < Event.Until); } else if (Event.Start < *start2 && Event.Count) { // Count= int count = Event.Count - 1; do { @@ -206,10 +244,13 @@ *end1 = *end1 + interval; INFO("** 1: (%s, %s) - %d", FormatCTime(*start1), FormatCTime(*end1), count); INFO(" 2: (%s, %s)", FormatCTime(*start2), FormatCTime(*end2)); + if (!RepeatMaskIntersects(start1, end1, start2, end2, Event)) { + continue; // we're not on a repeat cycle (e.g. wrong day of the week) + } if (TimeIntersects(start1, end1, start2, end2)) { return true; } - } while (--count); + } while (--count); } else if (Event.Start < *start2) { // no Count= and no Until= do { time_t interval = NextInterval(Event.RepeatFreq, (Event.Interval == 0) ? 1 : Event.Interval); @@ -217,16 +258,126 @@ *end1 = *end1 + interval; INFO("== 1: (%s, %s)", FormatCTime(*start1), FormatCTime(*end1)); INFO(" 2: (%s, %s)", FormatCTime(*start2), FormatCTime(*end2)); + if (!RepeatMaskIntersects(start1, end1, start2, end2, Event)) { + continue; // we're not on a repeat cycle (e.g. wrong day of the week) + } if (TimeIntersects(start1, end1, start2, end2)) { return true; } } while (*start1 < *end2); } } + //INFO(" no intersection"); return false; } - +// All the stuff between +// BEGIN:VEVENT +// ... +// END:VEVENT +// +void ParseEvent(Event_T * Event, char * pStart, int32_t tzoSec) +{ + if (strncmp(pStart, "DTSTART:", 8) == 0) { + Event->Start = ParseDateStamp(pStart+8, tzoSec); + //INFO(" Start: %d\r\n", mktime(&Event->eventStart)); + } else if (strncmp(pStart, "DTSTART;", 8) == 0) { + char * p = strrchr(pStart, ':'); + if (p) { + Event->Start = ParseDateStamp(p+1, tzoSec); + //INFO(" Start: %d\r\n", mktime(&Event->eventStart)); + } + } else if (strncmp(pStart, "DTEND:", 6) == 0) { + Event->End = ParseDateStamp(pStart+6, tzoSec); + //INFO(" End: %d\r\n", mktime(&Event->eventEnd)); + } else if (strncmp(pStart, "DTEND;", 6) == 0) { + char * p = strrchr(pStart, ':'); + if (p) { + Event->End = ParseDateStamp(p+1, tzoSec); + //INFO(" End: %d\r\n", mktime(&Event->eventEnd)); + } + } else if (strncmp(pStart, "SUMMARY:", 8) == 0) { + strncpy(Event->Summary, pStart+8, SUMMARY_CHARS-1); + Event->Summary[SUMMARY_CHARS-1] = '\0'; + //INFO(" Summary: %s\r\n", Event->Summary); + } else if (strncmp(pStart, "LOCATION:", 9) == 0) { + strncpy(Event->Location, pStart+9, LOCATION_CHARS-1); + Event->Location[LOCATION_CHARS-1] = '\0'; + //INFO(" Location: %s\r\n", Event->Location); + } else if (strncmp(pStart, "PRIORITY:", 9) == 0) { + Event->Priority = *(pStart+9) - '0'; + //INFO(" Priority: %d\r\n", Event->Priority); + } else if (strncmp(pStart, "CATEGORIES:", 11) == 0) { + strncpy(Event->Category, pStart+11, CATEGORY_CHARS-1); + Event->Category[CATEGORY_CHARS-1] = '\0'; + //INFO(" Category: %s\r\n", Event->Category); + } else if (strncmp(pStart, "RRULE:", 6) == 0) { + //RRULE:FREQ=WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR + char * p1, *p2; + //INFO("%s", pStart); + p1 = pStart + 6; // p1 = FREQ=WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR + p2 = strchr(p1, ';'); + if (p2) + *p2++ = '\0'; + while (*p1) { + //INFO("%s", p1); + if (strncmp(p1, "FREQ=", 5) == 0) { + //INFO("%s", p1); + p1 += 5; // p1 = WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR + if (strncmp(p1, "WEEKLY", 6) == 0) { + //INFO(" %s", p1); + Event->RepeatFreq = rptfWeekly; + p1 += 6; + } else if (strncmp(p1, "DAILY", 5) == 0) { + //INFO(" %s", p1); + Event->RepeatFreq = rptfDaily; + p1 += 5; + } else if (strncmp(p1, "MONTHLY", 7) == 0) { + //INFO(" %s", p1); + Event->RepeatFreq = rptfMonthly; + p1 += 7; + } else if (strncmp(p1, "YEARLY", 6) == 0) { + //INFO(" %s", p1); + Event->RepeatFreq = rptfYearly; + p1 += 7; + } + } else if (strncmp(p1, "INTERVAL=", 9) == 0) { // INTERVAL=2 + //INFO("%s", p1); + p1 += 9; + Event->Interval = atoi(p1); + } else if (strncmp(p1, "COUNT=", 6) == 0) { // COUNT=12; + //INFO("%s", p1); + p1 += 6; // p1 = + Event->Count = atoi(p1); + } else if (strncmp(p1, "UNTIL=", 6) == 0) { + //INFO("%s", p1); + p1 += 6; // p1 = 20140502T180000;BYDAY=MO,TU,WE,TH,FR + Event->Until = ParseDateStamp(p1, tzoSec); + } else if (strncmp(p1, "BYDAY=", 6) == 0) { + //INFO("%s", p1); + p1 += 6; // p1 = MO,TU,WE,TH,FR + while (*p1 >= ' ') { + //INFO(" %s", p1); + for (int d=0; d<7; d++) { + if (strncmp(p1,RepeatDayAbbrev(d),2) == 0) { + Event->RepeatDays |= (1 << d); + //INFO(" %s %02X", RepeatDayAbbrev(d), Event->RepeatDays); + break; + } + } + p1 += 3; + } + //INFO(" RepeatDay: %02X", Event->RepeatDays); + } + if (!p2) + break; + p1 = p2; + p2 = strchr(p1, ';'); + if (p2) + *p2++ = '\0'; + } + } +} void ParseICalStream(char * pStart, time_t gridStartTime, time_t gridEndTime, int32_t tzoSec) { @@ -236,7 +387,7 @@ typedef enum { idle, inTimeZone, inEvent } seekstate_t; seekstate_t seeking = idle; EventCount = 0; - + while (pStart && EventCount < EVENT_COUNT) { pEnd = strchr(pStart, '\n'); if (pEnd) { @@ -288,108 +439,12 @@ if (1 || Event.Start >= gridStartTime && Event.Start < gridEndTime || Event.End >= gridStartTime && Event.End < gridEndTime) { EventList[EventCount++] = Event; - INFO(" ++++++++++++ Added Event %d", EventCount); + INFO(" ++++++++++++ Added Event %d: %s", EventCount, Event.Summary); } seeking = idle; - } else if (strncmp(pStart, "DTSTART:", 8) == 0) { - Event.Start = ParseDateStamp(pStart+8, tzoSec); - //INFO(" Start: %d\r\n", mktime(&Event.eventStart)); - } else if (strncmp(pStart, "DTSTART;", 8) == 0) { - char * p = strrchr(pStart, ':'); - if (p) { - Event.Start = ParseDateStamp(p+1, tzoSec); - //INFO(" Start: %d\r\n", mktime(&Event.eventStart)); - } - } else if (strncmp(pStart, "DTEND:", 6) == 0) { - Event.End = ParseDateStamp(pStart+6, tzoSec); - //INFO(" End: %d\r\n", mktime(&Event.eventEnd)); - } else if (strncmp(pStart, "DTEND;", 6) == 0) { - char * p = strrchr(pStart, ':'); - if (p) { - Event.End = ParseDateStamp(p+1, tzoSec); - //INFO(" End: %d\r\n", mktime(&Event.eventEnd)); - } - } else if (strncmp(pStart, "SUMMARY:", 8) == 0) { - strncpy(Event.Summary, pStart+8, SUMMARY_CHARS-1); - Event.Summary[SUMMARY_CHARS-1] = '\0'; - //INFO(" Summary: %s\r\n", Event.Summary); - } else if (strncmp(pStart, "LOCATION:", 9) == 0) { - strncpy(Event.Location, pStart+9, LOCATION_CHARS-1); - Event.Location[LOCATION_CHARS-1] = '\0'; - //INFO(" Location: %s\r\n", Event.Location); - } else if (strncmp(pStart, "PRIORITY:", 9) == 0) { - Event.Priority = *(pStart+9) - '0'; - //INFO(" Priority: %d\r\n", Event.Priority); - } else if (strncmp(pStart, "CATEGORIES:", 11) == 0) { - strncpy(Event.Category, pStart+11, CATEGORY_CHARS-1); - Event.Category[CATEGORY_CHARS-1] = '\0'; - //INFO(" Category: %s\r\n", Event.Category); - } else if (strncmp(pStart, "RRULE:", 6) == 0) { - //RRULE:FREQ=WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR - char * p1, *p2; - INFO("%s", pStart); - p1 = pStart + 6; // p1 = FREQ=WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR - p2 = strchr(p1, ';'); - if (p2) - *p2++ = '\0'; - while (*p1) { - INFO("%s", p1); - if (strncmp(p1, "FREQ=", 5) == 0) { - INFO("%s", p1); - p1 += 5; // p1 = WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR - if (strncmp(p1, "WEEKLY", 6) == 0) { - INFO(" %s", p1); - Event.RepeatFreq = rptfWeekly; - p1 += 6; - } else if (strncmp(p1, "DAILY", 5) == 0) { - INFO(" %s", p1); - Event.RepeatFreq = rptfDaily; - p1 += 5; - } else if (strncmp(p1, "MONTHLY", 7) == 0) { - INFO(" %s", p1); - Event.RepeatFreq = rptfMonthly; - p1 += 7; - } else if (strncmp(p1, "YEARLY", 6) == 0) { - INFO(" %s", p1); - Event.RepeatFreq = rptfYearly; - p1 += 7; - } - } else if (strncmp(p1, "INTERVAL=", 9) == 0) { // INTERVAL=2 - INFO("%s", p1); - p1 += 9; - Event.Interval = atoi(p1); - } else if (strncmp(p1, "COUNT=", 6) == 0) { // COUNT=12; - INFO("%s", p1); - p1 += 6; // p1 = - Event.Count = atoi(p1); - } else if (strncmp(p1, "UNTIL=", 6) == 0) { - INFO("%s", p1); - p1 += 6; // p1 = 20140502T180000;BYDAY=MO,TU,WE,TH,FR - Event.Until = ParseDateStamp(p1, tzoSec); - } else if (strncmp(p1, "BYDAY=", 6) == 0) { - INFO("%s", p1); - p1 += 6; // p1 = MO,TU,WE,TH,FR - while (*p1 >= ' ') { - INFO(" %s", p1); - for (int d=0; d<7; d++) { - if (strncmp(p1,RepeatDayAbbrev(d),2) == 0) { - Event.RepeatDays |= (1 << d); - INFO(" %s %02X", RepeatDayAbbrev(d), Event.RepeatDays); - break; - } - } - p1 += 3; - } - INFO(" RepeatDay: %02X", Event.RepeatDays); - } - if (!p2) - break; - p1 = p2; - p2 = strchr(p1, ';'); - if (p2) - *p2++ = '\0'; - } - } + } else { + ParseEvent(&Event, pStart, tzoSec); + } // End of inEvent break; default: