]> granicus.if.org Git - icinga2/commitdiff
Implement complex 1.x timeperiod definitions.
authorGunnar Beutner <gunnar.beutner@netways.de>
Wed, 17 Apr 2013 12:26:04 +0000 (14:26 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Wed, 17 Apr 2013 12:26:04 +0000 (14:26 +0200)
lib/base/qstring.cpp
lib/base/qstring.h
lib/icinga/legacytimeperiod.cpp
lib/icinga/legacytimeperiod.h

index 1ae6cff0d6e4c44a1d49891cb945cdc3989a7ad9..c1ea8f3b4303a9e9a69e7111551b05dd2690d054 100644 (file)
@@ -122,6 +122,11 @@ size_t String::GetLength(void) const
        return m_Data.size();
 }
 
+size_t String::Find(const String& str, size_t pos) const
+{
+       return m_Data.find(str, pos);
+}
+
 size_t String::FindFirstOf(const char *s, size_t pos) const
 {
        return m_Data.find_first_of(s, pos);
index 5c7628e9dd431c640fbd6f69cc505fd94bc1e55e..e085045c355e3c3a6958b1b47527f5b32aa180b2 100644 (file)
@@ -75,6 +75,7 @@ public:
        void Clear(void);
        size_t GetLength(void) const;
 
+       size_t Find(const String& str, size_t pos = 0) const;
        size_t FindFirstOf(const char *s, size_t pos = 0) const;
        size_t FindFirstOf(char ch, size_t pos = 0) const;
        String SubStr(size_t first, size_t len = NPos) const;
index 8d9dae931fe138eb7c15c27c736b3b1604573115..262c473218a263a2409f8d8754102d82e455f1da 100644 (file)
@@ -33,32 +33,272 @@ using namespace icinga;
 
 REGISTER_SCRIPTFUNCTION(LegacyTimePeriod, &LegacyTimePeriod::ScriptFunc);
 
+bool LegacyTimePeriod::IsInTimeRange(tm *begin, tm *end, int stride, tm *reference)
+{
+       time_t tsbegin, tsend, tsref;
+       tsbegin = mktime(begin);
+       tsend = mktime(end);
+       tsref = mktime(reference);
+
+       if (tsref < tsbegin || tsref > tsend)
+               return false;
+
+       int daynumber = (tsref - tsbegin) / (24 * 60 * 60);
+
+       if (daynumber % stride == 0)
+               return false;
+
+       return true;
+}
+
+void LegacyTimePeriod::FindNthWeekday(int wday, int n, tm *reference)
+{
+       int seen = 0;
+
+       ASSERT(n > 0);
+
+       reference->tm_mday = 1;
+
+       for (;;) {
+               mktime(reference);
+
+               if (reference->tm_wday == wday) {
+                       seen++;
+
+                       if (seen == n)
+                               return;
+               }
+
+               reference->tm_mday++;
+       }
+}
+
+int LegacyTimePeriod::WeekdayFromString(const String& daydef)
+{
+       if (daydef == "sunday")
+               return 0;
+       else if (daydef == "monday")
+               return 1;
+       else if (daydef == "tuesday")
+               return 2;
+       else if (daydef == "wednesday")
+               return 3;
+       else if (daydef == "thursday")
+               return 4;
+       else if (daydef == "friday")
+               return 5;
+       else if (daydef == "saturday")
+               return 6;
+       else
+               return -1;
+}
+
+int LegacyTimePeriod::MonthFromString(const String& monthdef)
+{
+       if (monthdef == "january")
+               return 0;
+       else if (monthdef == "february")
+               return 1;
+       else if (monthdef == "march")
+               return 2;
+       else if (monthdef == "april")
+               return 3;
+       else if (monthdef == "may")
+               return 4;
+       else if (monthdef == "june")
+               return 5;
+       else if (monthdef == "july")
+               return 6;
+       else if (monthdef == "august")
+               return 7;
+       else if (monthdef == "september")
+               return 8;
+       else if (monthdef == "october")
+               return 9;
+       else if (monthdef == "november")
+               return 10;
+       else if (monthdef == "december")
+               return 11;
+       else
+               return -1;
+}
+
+void LegacyTimePeriod::ParseTimeSpec(const String& timespec, tm *begin, tm *end, tm *reference)
+{
+       /* YYYY-MM-DD */
+       if (timespec.GetLength() == 10 && timespec[4] == '-' && timespec[7] == '-') {
+               int year = Convert::ToLong(timespec.SubStr(0, 4));
+               int month = Convert::ToLong(timespec.SubStr(5, 2));
+               int day = Convert::ToLong(timespec.SubStr(7, 2));
+
+               if (begin) {
+                       begin->tm_year = year - 1900;
+                       begin->tm_mon = month;
+                       begin->tm_mday = day;
+                       begin->tm_hour = 0;
+                       begin->tm_min = 0;
+                       begin->tm_sec = 0;
+               }
+
+               if (end) {
+                       end->tm_year = year - 1900;
+                       end->tm_mon = month;
+                       end->tm_mday = day;
+                       end->tm_hour = 24;
+                       end->tm_min = 0;
+                       end->tm_sec = 0;
+               }
+
+               return;
+       }
+
+       std::vector<String> tokens;
+       boost::algorithm::split(tokens, timespec, boost::is_any_of(" "));
+
+       if (tokens.size() > 1 && tokens[0] == "day") {
+               int mday = Convert::ToLong(tokens[1]);
+
+               if (begin) {
+                       *begin = *reference;
+                       begin->tm_mday = mday;
+                       begin->tm_hour = 0;
+                       begin->tm_min = 0;
+                       begin->tm_sec = 0;
+
+                       /* Negative days are relative to the next month. */
+                       if (mday < 0) {
+                               end->tm_mday--;
+                               begin->tm_mon++;
+                       }
+               }
+
+               if (end) {
+                       *end = *reference;
+                       end->tm_mday = mday;
+                       end->tm_hour = 24;
+                       end->tm_min = 0;
+                       end->tm_sec = 0;
+
+                       /* Negative days are relative to the next month. */
+                       if (mday < 0) {
+                               end->tm_mday--;
+                               end->tm_mon++;
+                       }
+               }
+
+               return;
+       }
+
+       int wday;
+
+       if (tokens.size() > 1 && (wday = WeekdayFromString(tokens[0])) != -1) {
+               tm myref = *reference;
+
+               if (tokens.size() > 2) {
+                       int mon = MonthFromString(tokens[2]);
+
+                       if (mon == -1)
+                               BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid month in time specification: " + timespec));
+
+                       myref.tm_mon = mon;
+               }
+
+               int n = Convert::ToLong(tokens[1]);
+
+               if (begin) {
+                       *begin = myref;
+                       FindNthWeekday(wday, n, begin);
+                       begin->tm_hour = 0;
+                       begin->tm_min = 0;
+                       begin->tm_sec = 0;
+               }
+
+               if (end) {
+                       *end = myref;
+                       FindNthWeekday(wday, n, end);
+                       end->tm_hour = 0;
+                       end->tm_min = 0;
+                       end->tm_sec = 0;
+                       end->tm_mday++;
+               }
+
+               return;
+       }
+
+       BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid time specification: " + timespec));
+}
+
+void LegacyTimePeriod::ParseTimeRange(const String& timerange, tm *begin, tm *end, int *stride, tm *reference)
+{
+       String def = timerange;
+
+       /* Figure out the stride. */
+       size_t pos = def.FindFirstOf('/');
+
+       if (pos != String::NPos) {
+               String strStride = def.SubStr(pos + 1);
+               strStride.Trim();
+               *stride = Convert::ToLong(strStride);
+
+               /* Remove the stride parameter from the definition. */
+               def = def.SubStr(0, pos);
+       } else {
+               *stride = 1; /* User didn't specify anything, assume default. */
+       }
+
+       /* Figure out whether the user has specified two dates. */
+       pos = def.Find("- ");
+
+       std::cout << "XXX: " << def << std::endl;
+
+       if (pos != String::NPos) {
+               String first = def.SubStr(0, pos);
+               first.Trim();
+
+               String second = def.SubStr(pos + 1);
+               second.Trim();
+
+               ParseTimeSpec(first, begin, NULL, reference);
+
+               /* If the second definition starts with a number we need
+                * to add the first word from the first definition, e.g.:
+                * day 1 - 15 --> "day 15" */
+               bool is_number = true;
+               size_t xpos = second.FindFirstOf(' ');
+               String fword = second.SubStr(0, xpos);
+
+               try {
+                       Convert::ToLong(fword);
+               } catch (...) {
+                       is_number = false;
+               }
+
+               if (is_number) {
+                       xpos = first.FindFirstOf(' ');
+                       ASSERT(xpos != String::NPos);
+                       second = first.SubStr(0, xpos + 1) + second;
+               }
+
+               ParseTimeSpec(second, NULL, end, reference);
+       } else {
+               ParseTimeSpec(def, begin, end, reference);
+       }
+}
+
 bool LegacyTimePeriod::IsInDayDefinition(const String& daydef, tm *reference)
 {
-       if (daydef == "sunday" || daydef == "monday" || daydef == "tuesday" ||
-           daydef == "wednesday" || daydef == "thursday" || daydef == "friday" ||
-           daydef == "saturday") {
-               int wday;
-
-               if (daydef == "sunday")
-                       wday = 0;
-               else if (daydef == "monday")
-                       wday = 1;
-               else if (daydef == "tuesday")
-                       wday = 2;
-               else if (daydef == "wednesday")
-                       wday = 3;
-               else if (daydef == "thursday")
-                       wday = 4;
-               else if (daydef == "friday")
-                       wday = 5;
-               else if (daydef == "saturday")
-                       wday = 6;
+       /* Week specifications are special in that they don't have a reference frame. */
+       int wday = WeekdayFromString(daydef);
 
+       if (wday != -1)
                return reference->tm_wday == wday;
-       }
 
-       BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid day definition: " + daydef));
+       tm begin, end;
+       int stride;
+
+       ParseTimeRange(daydef, &begin, &end, &stride, reference);
+
+       return IsInTimeRange(&begin, &end, stride, reference);
 }
 
 Dictionary::Ptr LegacyTimePeriod::ProcessTimeRange(const String& timerange, tm *reference)
index 818f45020e0c59d684943b3b4931aaa46b9f0df8..131961fa3e807b560f401b5bc6f18d344cd041b0 100644 (file)
@@ -37,6 +37,12 @@ class I2_ICINGA_API LegacyTimePeriod
 public:
        static Array::Ptr ScriptFunc(const TimePeriod::Ptr& tp, double start, double end);
 
+       static bool IsInTimeRange(tm *begin, tm *end, int stride, tm *reference);
+       static void FindNthWeekday(int wday, int n, tm *reference);
+       static int WeekdayFromString(const String& daydef);
+       static int MonthFromString(const String& monthdef);
+       static void ParseTimeSpec(const String& timespec, tm *begin, tm *end, tm *reference);
+       static void ParseTimeRange(const String& timerange, tm *begin, tm *end, int *stride, tm *reference);
        static bool IsInDayDefinition(const String& daydef, tm *reference);
        static Dictionary::Ptr ProcessTimeRange(const String& timerange, tm *reference);
        static void ProcessTimeRanges(const String& timeranges, tm *reference, const Array::Ptr& result);