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 // Add %#q for fractional seconds to standard strptime function
strptime(const char * s,const char * format)25 char* log_time::strptime(const char* s, const char* format) {
26   time_t now;
27 #ifdef __linux__
28   *this = log_time(CLOCK_REALTIME);
29   now = tv_sec;
30 #else
31   time(&now);
32   tv_sec = now;
33   tv_nsec = 0;
34 #endif
35 
36   struct tm* ptm;
37 #if !defined(_WIN32)
38   struct tm tmBuf;
39   ptm = localtime_r(&now, &tmBuf);
40 #else
41   ptm = localtime(&now);
42 #endif
43 
44   char fmt[strlen(format) + 1];
45   strcpy(fmt, format);
46 
47   char* ret = const_cast<char*>(s);
48   char* cp;
49   for (char* f = cp = fmt;; ++cp) {
50     if (!*cp) {
51       if (f != cp) {
52         ret = ::strptime(ret, f, ptm);
53       }
54       break;
55     }
56     if (*cp != '%') {
57       continue;
58     }
59     char* e = cp;
60     ++e;
61 #if (defined(__BIONIC__))
62     if (*e == 's') {
63       *cp = '\0';
64       if (*f) {
65         ret = ::strptime(ret, f, ptm);
66         if (!ret) {
67           break;
68         }
69       }
70       tv_sec = 0;
71       while (isdigit(*ret)) {
72         tv_sec = tv_sec * 10 + *ret - '0';
73         ++ret;
74       }
75       now = tv_sec;
76 #if !defined(_WIN32)
77       ptm = localtime_r(&now, &tmBuf);
78 #else
79       ptm = localtime(&now);
80 #endif
81     } else
82 #endif
83     {
84       unsigned num = 0;
85       while (isdigit(*e)) {
86         num = num * 10 + *e - '0';
87         ++e;
88       }
89       if (*e != 'q') {
90         continue;
91       }
92       *cp = '\0';
93       if (*f) {
94         ret = ::strptime(ret, f, ptm);
95         if (!ret) {
96           break;
97         }
98       }
99       unsigned long mul = NS_PER_SEC;
100       if (num == 0) {
101         num = INT_MAX;
102       }
103       tv_nsec = 0;
104       while (isdigit(*ret) && num && (mul > 1)) {
105         --num;
106         mul /= 10;
107         tv_nsec = tv_nsec + (*ret - '0') * mul;
108         ++ret;
109       }
110     }
111     f = cp = e;
112     ++f;
113   }
114 
115   if (ret) {
116     tv_sec = mktime(ptm);
117     return ret;
118   }
119 
120 // Upon error, place a known value into the class, the current time.
121 #ifdef __linux__
122   *this = log_time(CLOCK_REALTIME);
123 #else
124   time(&now);
125   tv_sec = now;
126   tv_nsec = 0;
127 #endif
128   return ret;
129 }
130