time_zone_posix.cc
Go to the documentation of this file.
00001 // Copyright 2016 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //   https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 //   Unless required by applicable law or agreed to in writing, software
00010 //   distributed under the License is distributed on an "AS IS" BASIS,
00011 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 //   See the License for the specific language governing permissions and
00013 //   limitations under the License.
00014 
00015 #include "time_zone_posix.h"
00016 
00017 #include <cstddef>
00018 #include <cstring>
00019 #include <limits>
00020 #include <string>
00021 
00022 namespace absl {
00023 namespace time_internal {
00024 namespace cctz {
00025 
00026 namespace {
00027 
00028 const char kDigits[] = "0123456789";
00029 
00030 const char* ParseInt(const char* p, int min, int max, int* vp) {
00031   int value = 0;
00032   const char* op = p;
00033   const int kMaxInt = std::numeric_limits<int>::max();
00034   for (; const char* dp = strchr(kDigits, *p); ++p) {
00035     int d = static_cast<int>(dp - kDigits);
00036     if (d >= 10) break;  // '\0'
00037     if (value > kMaxInt / 10) return nullptr;
00038     value *= 10;
00039     if (value > kMaxInt - d) return nullptr;
00040     value += d;
00041   }
00042   if (p == op || value < min || value > max) return nullptr;
00043   *vp = value;
00044   return p;
00045 }
00046 
00047 // abbr = <.*?> | [^-+,\d]{3,}
00048 const char* ParseAbbr(const char* p, std::string* abbr) {
00049   const char* op = p;
00050   if (*p == '<') {  // special zoneinfo <...> form
00051     while (*++p != '>') {
00052       if (*p == '\0') return nullptr;
00053     }
00054     abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1);
00055     return ++p;
00056   }
00057   while (*p != '\0') {
00058     if (strchr("-+,", *p)) break;
00059     if (strchr(kDigits, *p)) break;
00060     ++p;
00061   }
00062   if (p - op < 3) return nullptr;
00063   abbr->assign(op, static_cast<std::size_t>(p - op));
00064   return p;
00065 }
00066 
00067 // offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value)
00068 const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign,
00069                         std::int_fast32_t* offset) {
00070   if (p == nullptr) return nullptr;
00071   if (*p == '+' || *p == '-') {
00072     if (*p++ == '-') sign = -sign;
00073   }
00074   int hours = 0;
00075   int minutes = 0;
00076   int seconds = 0;
00077 
00078   p = ParseInt(p, min_hour, max_hour, &hours);
00079   if (p == nullptr) return nullptr;
00080   if (*p == ':') {
00081     p = ParseInt(p + 1, 0, 59, &minutes);
00082     if (p == nullptr) return nullptr;
00083     if (*p == ':') {
00084       p = ParseInt(p + 1, 0, 59, &seconds);
00085       if (p == nullptr) return nullptr;
00086     }
00087   }
00088   *offset = sign * ((((hours * 60) + minutes) * 60) + seconds);
00089   return p;
00090 }
00091 
00092 // datetime = ( Jn | n | Mm.w.d ) [ / offset ]
00093 const char* ParseDateTime(const char* p, PosixTransition* res) {
00094   if (p != nullptr && *p == ',') {
00095     if (*++p == 'M') {
00096       int month = 0;
00097       if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') {
00098         int week = 0;
00099         if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') {
00100           int weekday = 0;
00101           if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
00102             res->date.fmt = PosixTransition::M;
00103             res->date.m.month = static_cast<int_fast8_t>(month);
00104             res->date.m.week = static_cast<int_fast8_t>(week);
00105             res->date.m.weekday = static_cast<int_fast8_t>(weekday);
00106           }
00107         }
00108       }
00109     } else if (*p == 'J') {
00110       int day = 0;
00111       if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) {
00112         res->date.fmt = PosixTransition::J;
00113         res->date.j.day = static_cast<int_fast16_t>(day);
00114       }
00115     } else {
00116       int day = 0;
00117       if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
00118         res->date.fmt = PosixTransition::N;
00119         res->date.j.day = static_cast<int_fast16_t>(day);
00120       }
00121     }
00122   }
00123   if (p != nullptr) {
00124     res->time.offset = 2 * 60 * 60;  // default offset is 02:00:00
00125     if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
00126   }
00127   return p;
00128 }
00129 
00130 }  // namespace
00131 
00132 // spec = std offset [ dst [ offset ] , datetime , datetime ]
00133 bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
00134   const char* p = spec.c_str();
00135   if (*p == ':') return false;
00136 
00137   p = ParseAbbr(p, &res->std_abbr);
00138   p = ParseOffset(p, 0, 24, -1, &res->std_offset);
00139   if (p == nullptr) return false;
00140   if (*p == '\0') return true;
00141 
00142   p = ParseAbbr(p, &res->dst_abbr);
00143   if (p == nullptr) return false;
00144   res->dst_offset = res->std_offset + (60 * 60);  // default
00145   if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset);
00146 
00147   p = ParseDateTime(p, &res->dst_start);
00148   p = ParseDateTime(p, &res->dst_end);
00149 
00150   return p != nullptr && *p == '\0';
00151 }
00152 
00153 }  // namespace cctz
00154 }  // namespace time_internal
00155 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15