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