an iCal processing library

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Sun Jun 22 20:52:26 2014 +0000
Parent:
4:a1c25d936346
Child:
6:4d1fc1cb38ad
Commit message:
Revise the parsing and time zone management.

Changed in this revision

iCal.cpp Show annotated file Show diff for this revision Revisions of this file
iCal.h Show annotated file Show diff for this revision Revisions of this file
--- a/iCal.cpp	Sun Jun 08 01:35:37 2014 +0000
+++ b/iCal.cpp	Sun Jun 22 20:52:26 2014 +0000
@@ -9,14 +9,14 @@
 #include "iCal.h"
 #include <algorithm>
 
-#ifdef _DEBUG
+//#ifdef _DEBUG
 #define DEBUG "iCal"
-#endif
+//#endif
 #ifdef WIN32
 #define LF "\n"
-#else
+#else // mbed
 #define LF "\r\n"
-#endif
+#endif // WIN32
 #include <cstdio>
 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
 #define DBG(x, ...)  std::printf("[DBG %s %3d] " x LF, DEBUG, __LINE__, ##__VA_ARGS__)
@@ -80,7 +80,8 @@
 }
 
 // YYYYMMDD[THHMMSS[Z]]
-time_t ParseDateStamp(char * string, int32_t tzoSec)
+// VALUE=DATE:YYYYMMDD
+time_t ParseDateStamp(char * string, tz_sec_t tzoSec)
 {
     time_t tStamp;
     struct tm t;
@@ -88,6 +89,9 @@
 
     time(&tStamp);
     tnow = localtime(&tStamp);
+    if (strncmp(string, "VALUE=DATE:", 11) == 0) {
+        string += 11;
+    }
     //INFO("ParseDateStamp(%s,%d)\n", string, tzoSec);
     t.tm_year = AtoIxN(string, 4) - 1900;
     t.tm_mon  = AtoIxN(string+4, 2) - 1;
@@ -233,7 +237,7 @@
     int delta = repeatFactor[repeatFreq];
     if (repeatFreq == 4 && isLeapYear(curTime))
         delta += 1;
-    INFO("freq %d, interval %d, delta %d", repeatFreq, interval, delta);
+    //INFO("freq %d, interval %d, delta %d", repeatFreq, interval, delta);
     return delta * interval * secperday;
 }
 
@@ -248,9 +252,9 @@
 {
     bool intersects = false;
     
-    INFO("RepeatFreq: %d", Event->RepeatFreq);
+    //INFO("RepeatFreq: %d", Event->RepeatFreq);
     if (Event->RepeatFreq == rptfDaily) {
-        INFO("rptfDaily is not handled");
+        //INFO("rptfDaily is not handled");
     } else if (Event->RepeatFreq == rptfWeekly) {
         struct tm * timeinfo;
         timeinfo = localtime(start1);
@@ -267,7 +271,7 @@
     } else if (Event->RepeatFreq == rptfYearly) {
         //struct tm * timeinfo;
         //timeinfo = localtime(start1);
-        INFO("rptfYearly is not handled");        
+        //INFO("rptfYearly is not handled well yet");        
     }
     //INFO("Mask: no handler, returning true");
     return true;
@@ -276,21 +280,21 @@
 bool RepeatIntersects(time_t * start1, time_t * end1, time_t * start2, time_t * end2, Event_T * Event)
 {
     
-    INFO("** 1: (%s, %s)", FormatCTime(*start1), *end1 ? FormatCTime(*end1) : "");
-    INFO("   2: (%s, %s)", FormatCTime(*start2), *end2 ? FormatCTime(*end2) : "");
+    //INFO("** 1: (%s, %s)", FormatCTime(*start1), *end1 ? FormatCTime(*end1) : "");
+    //INFO("   2: (%s, %s)", FormatCTime(*start2), *end2 ? FormatCTime(*end2) : "");
     if (TimeIntersects(start1, end1, start2, end2))
         return true;
     if (Event && Event->RepeatFreq) {
-        INFO("Summary: %s", Event->Summary);
+        //INFO("Summary: %s", Event->Summary);
         if (Event->Start < *start2 && Event->Until > *start2 ) {           // Until=....
             do {
                 time_t interval = NextInterval(*start1, Event->RepeatFreq, (Event->Interval == 0) ? 1 : Event->Interval);
                 *start1 = *start1 + interval;
                 if (*end1)
                     *end1   = *end1   + interval;
-                INFO("** 1: (%s, %s)", FormatCTime(*start1), *end1 ? FormatCTime(*end1) : "");
-                INFO("until (%24s, %s)", " ", FormatCTime(Event->Until));
-                INFO("   2: (%s, %s)", FormatCTime(*start2), *end2 ? FormatCTime(*end2) : "");
+                //INFO("** 1: (%s, %s)", FormatCTime(*start1), *end1 ? FormatCTime(*end1) : "");
+                //INFO("until (%24s, %s)", " ", FormatCTime(Event->Until));
+                //INFO("   2: (%s, %s)", FormatCTime(*start2), *end2 ? FormatCTime(*end2) : "");
                 if (!RepeatMaskIntersects(start1, end1, start2, end2, Event)) {
                     continue;   // we're not on a repeat cycle (e.g. wrong day of the week)
                 }
@@ -305,8 +309,8 @@
                 *start1 = *start1 + interval;
                 if (*end1)
                     *end1   = *end1   + interval;
-                INFO("** 1: (%s, %s) - %d", FormatCTime(*start1), *end1 ? FormatCTime(*end1) : "", count);
-                INFO("   2: (%s, %s)", FormatCTime(*start2), *end2 ? FormatCTime(*end2) : "");
+                //INFO("** 1: (%s, %s) - %d", FormatCTime(*start1), *end1 ? FormatCTime(*end1) : "", count);
+                //INFO("   2: (%s, %s)", FormatCTime(*start2), *end2 ? FormatCTime(*end2) : "");
                 if (!RepeatMaskIntersects(start1, end1, start2, end2, Event)) {
                     continue;   // we're not on a repeat cycle (e.g. wrong day of the week)
                 }
@@ -323,8 +327,8 @@
                 *start1 = *start1 + interval;
                 if (*end1)
                     *end1   = *end1   + interval;
-                INFO("== 1: (%s, %s)", FormatCTime(*start1), *end1 ? FormatCTime(*end1) : "");
-                INFO("   2: (%s, %s)", FormatCTime(*start2), *end2 ? FormatCTime(*end2) : "");
+                //INFO("== 1: (%s, %s)", FormatCTime(*start1), *end1 ? FormatCTime(*end1) : "");
+                //INFO("   2: (%s, %s)", FormatCTime(*start2), *end2 ? FormatCTime(*end2) : "");
                 if (!RepeatMaskIntersects(start1, end1, start2, end2, Event)) {
                     continue;   // we're not on a repeat cycle (e.g. wrong day of the week)
                 }
@@ -343,8 +347,9 @@
 // ...
 // END:VEVENT
 //
-void ParseEvent(Event_T * Event, char * pStart, int32_t tzoSec)
+void ParseEvent(Event_T * Event, char * pStart, tz_sec_t tzoSec)
 {
+    INFO("ParseEvent(...,'%s',%d)", pStart, tzoSec);
     if (strncmp(pStart, "DTSTART:", 8) == 0) {
         Event->Start = ParseDateStamp(pStart+8, tzoSec);
         //INFO("  Start: %d\n", mktime(&Event->eventStart));
@@ -354,7 +359,7 @@
         p = strrchr(pStart, ':');
         if (p) {
             Event->Start = ParseDateStamp(p+1, tzoSec);
-            //INFO("  Start: %d\n", mktime(&Event->eventStart));
+            INFO("  Start: %s\n", ctime(&Event->Start));
         }
     } else if (strncmp(pStart, "DTEND:", 6) == 0) {
         Event->End = ParseDateStamp(pStart+6, tzoSec);
@@ -365,7 +370,7 @@
         p = strrchr(pStart, ':');
         if (p) {
             Event->End = ParseDateStamp(p+1, tzoSec);
-            //INFO("    End: %d\n", mktime(&Event->eventEnd));
+            INFO("    End: %s\n", ctime(&Event->End));
         }
     } else if (strncmp(pStart, "SUMMARY:", 8) == 0) {
         strncpy(Event->Summary, pStart+8, SUMMARY_CHARS-1);
@@ -492,11 +497,12 @@
 // TZID="(GMT -06:00)":20140519T063000
 // TZID:(UTC-06:00) Central Time (US & Canada)
 // TZID:(GMT -06:00)
-int32_t ParseTZID(char * string)
+tz_sec_t ParseTZID(char * string)
 {
-    int32_t tzo = 0;
+    tz_sec_t tzo = 0;
     bool sign = false;
 
+    INFO("ParseTZID(%s)", string);
     if (*string == '"')     // TZID="(GMT -06:00)":20140519T063000 
         string++;
     if ((strncmp(string, "(UTC", 4) == 0) 
@@ -516,13 +522,14 @@
         }
         if (sign)
             tzo = -tzo;
+        INFO("  tzo = %d", tzo);
     } else {
         ERR("Unhandled TZID(%s)", string);
     }
     return tzo;
 }
 
-int ParseICalStream(char * pStart, time_t gridStartTime, time_t gridEndTime, int32_t tzoSec, bool showEvents)
+int ParseICalStream(char * pStart, time_t gridStartTime, time_t gridEndTime, tz_min_t tzoMin, bool showEvents)
 {
     Event_T Event;
     bool tzAdjusted = false;
@@ -543,8 +550,8 @@
                 pEnd++;
             }
             // pStart now has a single null terminated line of text.
-            if (showEvents)
-                INFO("*** %s", pStart);
+            //if (showEvents)
+                //INFO("*** %s", pStart);
             switch (seeking) {
                 case idle:
                     if (strcmp(pStart, "BEGIN:VTIMEZONE") == 0)
@@ -583,9 +590,9 @@
                     if (strcmp(pStart, "END:VEVENT") == 0) {
                         // Timezone offset
                         if (!tzAdjusted) {
-                            Event.Start += tzoSec;
+                            Event.Start += (60 * tzoMin);
                             if (Event.End)
-                                Event.End   += tzoSec;
+                                Event.End += (60 * tzoMin);
                         }
                         // Process it
                         if (showEvents)
@@ -598,7 +605,7 @@
                         }
                         seeking = idle;
                     } else {
-                        ParseEvent(&Event, pStart, tzoSec);
+                        ParseEvent(&Event, pStart, 60 * tzoMin);
                     }
                     // End of inEvent
                     break;
--- a/iCal.h	Sun Jun 08 01:35:37 2014 +0000
+++ b/iCal.h	Sun Jun 22 20:52:26 2014 +0000
@@ -2,10 +2,12 @@
 #define ICAL_H
 #include "mbed.h"
 
-//#include "NTPClient.h"
-
 // This defines the total number of events that can be handled - kind of limiting
-// but maybe ok for now.
+// but maybe ok for now. This is a kind of trade-off, based on having to receive
+// the whole iCal file into a buffer, and that not leaving a lot left over for
+// events themselves. Instead, the receive process should do more "on the fly"
+// with a then smaller buffer, leaving room for many more events. Possibly too,
+// the events could be quickly rejected if not matching the criteria.
 #define EVENT_COUNT 10
 
 
@@ -40,6 +42,9 @@
 } RepeatDays_t;
 #endif
 
+typedef int32_t tz_sec_t;
+typedef int16_t tz_min_t;
+
 typedef struct {
     time_t Start;
     time_t End;
@@ -70,11 +75,11 @@
 /// @param[in] pStart is a pointer to the start of the stream.
 /// @param[in] gridStartTime is a time value representing the start of the time-window of interest.
 /// @param[in] gridEndTime is a time value representing the end of the time-window of interest.
-/// @param[in] tzoSec is the time-zone offset in seconds.
+/// @param[in] tzoMin is the time-zone offset in minutes.
 /// @param[in] showEvents when true causes it to print the events as parsed.
 /// @returns number of events in range.
 ///
-int ParseICalStream(char * pStart, time_t gridStartTime, time_t gridEndTime, int32_t tzoSec, bool showEvents = false);
+int ParseICalStream(char * pStart, time_t gridStartTime, time_t gridEndTime, tz_min_t tzoMin, bool showEvents = false);
 
 
 /// Get the number of events that have been cached.
@@ -177,7 +182,7 @@
 /// @param[in] tzoSec is the time-zone offset in seconds.
 /// @returns time_t value.
 ///
-time_t ParseDateStamp(char * string, int32_t tzoSec);
+time_t ParseDateStamp(char * string, tz_sec_t tzoSec);
 
 /// Parse a Time Zone ID value from the front-end of a Datestamp
 ///
@@ -189,7 +194,7 @@
 /// @param[in] string to be parsed.
 /// @returns time zone offset in seconds.
 ///
-int32_t ParseTZID(char * string);
+tz_sec_t ParseTZID(char * string);