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 const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
25 const timespec log_time::EPOCH = {0, 0};
26
27 // Add %#q for fractional seconds to standard strptime function
28
strptime(const char * s,const char * format)29 char* log_time::strptime(const char* s, const char* format) {
30 time_t now;
31 #ifdef __linux__
32 *this = log_time(CLOCK_REALTIME);
33 now = tv_sec;
34 #else
35 time(&now);
36 tv_sec = now;
37 tv_nsec = 0;
38 #endif
39
40 struct tm* ptm;
41 #if !defined(_WIN32)
42 struct tm tmBuf;
43 ptm = localtime_r(&now, &tmBuf);
44 #else
45 ptm = localtime(&now);
46 #endif
47
48 char fmt[strlen(format) + 1];
49 strcpy(fmt, format);
50
51 char* ret = const_cast<char*>(s);
52 char* cp;
53 for (char* f = cp = fmt;; ++cp) {
54 if (!*cp) {
55 if (f != cp) {
56 ret = ::strptime(ret, f, ptm);
57 }
58 break;
59 }
60 if (*cp != '%') {
61 continue;
62 }
63 char* e = cp;
64 ++e;
65 #if (defined(__BIONIC__))
66 if (*e == 's') {
67 *cp = '\0';
68 if (*f) {
69 ret = ::strptime(ret, f, ptm);
70 if (!ret) {
71 break;
72 }
73 }
74 tv_sec = 0;
75 while (isdigit(*ret)) {
76 tv_sec = tv_sec * 10 + *ret - '0';
77 ++ret;
78 }
79 now = tv_sec;
80 #if !defined(_WIN32)
81 ptm = localtime_r(&now, &tmBuf);
82 #else
83 ptm = localtime(&now);
84 #endif
85 } else
86 #endif
87 {
88 unsigned num = 0;
89 while (isdigit(*e)) {
90 num = num * 10 + *e - '0';
91 ++e;
92 }
93 if (*e != 'q') {
94 continue;
95 }
96 *cp = '\0';
97 if (*f) {
98 ret = ::strptime(ret, f, ptm);
99 if (!ret) {
100 break;
101 }
102 }
103 unsigned long mul = NS_PER_SEC;
104 if (num == 0) {
105 num = INT_MAX;
106 }
107 tv_nsec = 0;
108 while (isdigit(*ret) && num && (mul > 1)) {
109 --num;
110 mul /= 10;
111 tv_nsec = tv_nsec + (*ret - '0') * mul;
112 ++ret;
113 }
114 }
115 f = cp = e;
116 ++f;
117 }
118
119 if (ret) {
120 tv_sec = mktime(ptm);
121 return ret;
122 }
123
124 // Upon error, place a known value into the class, the current time.
125 #ifdef __linux__
126 *this = log_time(CLOCK_REALTIME);
127 #else
128 time(&now);
129 tv_sec = now;
130 tv_nsec = 0;
131 #endif
132 return ret;
133 }
134
operator -=(const timespec & T)135 log_time log_time::operator-=(const timespec& T) {
136 // No concept of negative time, clamp to EPOCH
137 if (*this <= T) {
138 return *this = log_time(EPOCH);
139 }
140
141 if (this->tv_nsec < (unsigned long int)T.tv_nsec) {
142 --this->tv_sec;
143 this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
144 } else {
145 this->tv_nsec -= T.tv_nsec;
146 }
147 this->tv_sec -= T.tv_sec;
148
149 return *this;
150 }
151
operator +=(const timespec & T)152 log_time log_time::operator+=(const timespec& T) {
153 this->tv_nsec += (unsigned long int)T.tv_nsec;
154 if (this->tv_nsec >= NS_PER_SEC) {
155 this->tv_nsec -= NS_PER_SEC;
156 ++this->tv_sec;
157 }
158 this->tv_sec += T.tv_sec;
159
160 return *this;
161 }
162
operator -=(const log_time & T)163 log_time log_time::operator-=(const log_time& T) {
164 // No concept of negative time, clamp to EPOCH
165 if (*this <= T) {
166 return *this = log_time(EPOCH);
167 }
168
169 if (this->tv_nsec < T.tv_nsec) {
170 --this->tv_sec;
171 this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
172 } else {
173 this->tv_nsec -= T.tv_nsec;
174 }
175 this->tv_sec -= T.tv_sec;
176
177 return *this;
178 }
179
operator +=(const log_time & T)180 log_time log_time::operator+=(const log_time& T) {
181 this->tv_nsec += T.tv_nsec;
182 if (this->tv_nsec >= NS_PER_SEC) {
183 this->tv_nsec -= NS_PER_SEC;
184 ++this->tv_sec;
185 }
186 this->tv_sec += T.tv_sec;
187
188 return *this;
189 }
190