00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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;
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
00048 const char* ParseAbbr(const char* p, std::string* abbr) {
00049 const char* op = p;
00050 if (*p == '<') {
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
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
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;
00125 if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
00126 }
00127 return p;
00128 }
00129
00130 }
00131
00132
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);
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 }
00154 }
00155 }