1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <ctype.h>
18#include <limits.h>
19#include <stdio.h>
20#include <string.h>
21
22#include <private/android_logger.h>
23
24#include "log_portability.h"
25
26LIBLOG_ABI_PRIVATE const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
27LIBLOG_ABI_PRIVATE const timespec log_time::EPOCH = { 0, 0 };
28
29// Add %#q for fractional seconds to standard strptime function
30
31LIBLOG_ABI_PRIVATE char* log_time::strptime(const char* s, const char* format) {
32  time_t now;
33#ifdef __linux__
34  *this = log_time(CLOCK_REALTIME);
35  now = tv_sec;
36#else
37  time(&now);
38  tv_sec = now;
39  tv_nsec = 0;
40#endif
41
42  struct tm* ptm;
43#if !defined(_WIN32)
44  struct tm tmBuf;
45  ptm = localtime_r(&now, &tmBuf);
46#else
47  ptm = localtime(&now);
48#endif
49
50  char fmt[strlen(format) + 1];
51  strcpy(fmt, format);
52
53  char* ret = const_cast<char*>(s);
54  char* cp;
55  for (char* f = cp = fmt;; ++cp) {
56    if (!*cp) {
57      if (f != cp) {
58        ret = ::strptime(ret, f, ptm);
59      }
60      break;
61    }
62    if (*cp != '%') {
63      continue;
64    }
65    char* e = cp;
66    ++e;
67#if (defined(__BIONIC__))
68    if (*e == 's') {
69      *cp = '\0';
70      if (*f) {
71        ret = ::strptime(ret, f, ptm);
72        if (!ret) {
73          break;
74        }
75      }
76      tv_sec = 0;
77      while (isdigit(*ret)) {
78        tv_sec = tv_sec * 10 + *ret - '0';
79        ++ret;
80      }
81      now = tv_sec;
82#if !defined(_WIN32)
83      ptm = localtime_r(&now, &tmBuf);
84#else
85      ptm = localtime(&now);
86#endif
87    } else
88#endif
89    {
90      unsigned num = 0;
91      while (isdigit(*e)) {
92        num = num * 10 + *e - '0';
93        ++e;
94      }
95      if (*e != 'q') {
96        continue;
97      }
98      *cp = '\0';
99      if (*f) {
100        ret = ::strptime(ret, f, ptm);
101        if (!ret) {
102          break;
103        }
104      }
105      unsigned long mul = NS_PER_SEC;
106      if (num == 0) {
107        num = INT_MAX;
108      }
109      tv_nsec = 0;
110      while (isdigit(*ret) && num && (mul > 1)) {
111        --num;
112        mul /= 10;
113        tv_nsec = tv_nsec + (*ret - '0') * mul;
114        ++ret;
115      }
116    }
117    f = cp = e;
118    ++f;
119  }
120
121  if (ret) {
122    tv_sec = mktime(ptm);
123    return ret;
124  }
125
126// Upon error, place a known value into the class, the current time.
127#ifdef __linux__
128  *this = log_time(CLOCK_REALTIME);
129#else
130  time(&now);
131  tv_sec = now;
132  tv_nsec = 0;
133#endif
134  return ret;
135}
136
137LIBLOG_ABI_PRIVATE log_time log_time::operator-=(const timespec& T) {
138  // No concept of negative time, clamp to EPOCH
139  if (*this <= T) {
140    return *this = EPOCH;
141  }
142
143  if (this->tv_nsec < (unsigned long int)T.tv_nsec) {
144    --this->tv_sec;
145    this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
146  } else {
147    this->tv_nsec -= T.tv_nsec;
148  }
149  this->tv_sec -= T.tv_sec;
150
151  return *this;
152}
153
154LIBLOG_ABI_PRIVATE log_time log_time::operator+=(const timespec& T) {
155  this->tv_nsec += (unsigned long int)T.tv_nsec;
156  if (this->tv_nsec >= NS_PER_SEC) {
157    this->tv_nsec -= NS_PER_SEC;
158    ++this->tv_sec;
159  }
160  this->tv_sec += T.tv_sec;
161
162  return *this;
163}
164
165LIBLOG_ABI_PRIVATE log_time log_time::operator-=(const log_time& T) {
166  // No concept of negative time, clamp to EPOCH
167  if (*this <= T) {
168    return *this = EPOCH;
169  }
170
171  if (this->tv_nsec < T.tv_nsec) {
172    --this->tv_sec;
173    this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
174  } else {
175    this->tv_nsec -= T.tv_nsec;
176  }
177  this->tv_sec -= T.tv_sec;
178
179  return *this;
180}
181
182LIBLOG_ABI_PRIVATE log_time log_time::operator+=(const log_time& T) {
183  this->tv_nsec += T.tv_nsec;
184  if (this->tv_nsec >= NS_PER_SEC) {
185    this->tv_nsec -= NS_PER_SEC;
186    ++this->tv_sec;
187  }
188  this->tv_sec += T.tv_sec;
189
190  return *this;
191}
192