1 /*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2015-2019 Derick Rethans
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * Portions copyright (c) 1998-2017 Zend Technologies Ltd.
25 *
26 * The timelib_strcasecmp and timelib_strncasecmp are taken from PHP's
27 * Zend/zend_operators.[hc] source files.
28 *
29 */
30
31 #include "timelib.h"
32 #include "timelib_private.h"
33 #include <ctype.h>
34 #include <math.h>
35
36 #define TIMELIB_LLABS(y) (y < 0 ? (y * -1) : y)
37
38 const char *timelib_error_messages[8] = {
39 "No error",
40 "Can not allocate buffer for parsing",
41 "Corrupt tzfile: The transitions in the file don't always increase",
42 "Corrupt tzfile: The expected 64-bit preamble is missing",
43 "Corrupt tzfile: No abbreviation could be found for a transition",
44 "The version used in this timezone identifier is unsupported",
45 "No timezone with this name could be found",
46 };
47
timelib_get_error_message(int error_code)48 const char *timelib_get_error_message(int error_code)
49 {
50 int entries = sizeof(timelib_error_messages) / sizeof(char*);
51
52 if (error_code >= 0 && error_code < entries) {
53 return timelib_error_messages[error_code];
54 }
55 return "Unknown error code";
56 }
57
timelib_time_ctor(void)58 timelib_time* timelib_time_ctor(void)
59 {
60 timelib_time *t;
61 t = timelib_calloc(1, sizeof(timelib_time));
62
63 return t;
64 }
65
timelib_time_dtor(timelib_time * t)66 void timelib_time_dtor(timelib_time* t)
67 {
68 TIMELIB_TIME_FREE(t->tz_abbr);
69 TIMELIB_TIME_FREE(t);
70 }
71
timelib_time_compare(timelib_time * t1,timelib_time * t2)72 int timelib_time_compare(timelib_time *t1, timelib_time *t2)
73 {
74 if (t1->sse == t2->sse) {
75 if (t1->us == t2->us) {
76 return 0;
77 }
78
79 return (t1->us < t2->us) ? -1 : 1;
80 }
81
82 return (t1->sse < t2->sse) ? -1 : 1;
83 }
84
timelib_time_clone(timelib_time * orig)85 timelib_time* timelib_time_clone(timelib_time *orig)
86 {
87 timelib_time *tmp = timelib_time_ctor();
88 memcpy(tmp, orig, sizeof(timelib_time));
89 if (orig->tz_abbr) {
90 tmp->tz_abbr = timelib_strdup(orig->tz_abbr);
91 }
92 if (orig->tz_info) {
93 tmp->tz_info = orig->tz_info;
94 }
95 return tmp;
96 }
97
timelib_rel_time_ctor(void)98 timelib_rel_time* timelib_rel_time_ctor(void)
99 {
100 timelib_rel_time *t;
101 t = timelib_calloc(1, sizeof(timelib_rel_time));
102
103 return t;
104 }
105
timelib_rel_time_dtor(timelib_rel_time * t)106 void timelib_rel_time_dtor(timelib_rel_time* t)
107 {
108 TIMELIB_TIME_FREE(t);
109 }
110
timelib_rel_time_clone(timelib_rel_time * rel)111 timelib_rel_time* timelib_rel_time_clone(timelib_rel_time *rel)
112 {
113 timelib_rel_time *tmp = timelib_rel_time_ctor();
114 memcpy(tmp, rel, sizeof(timelib_rel_time));
115 return tmp;
116 }
117
timelib_time_tz_abbr_update(timelib_time * tm,char * tz_abbr)118 void timelib_time_tz_abbr_update(timelib_time* tm, char* tz_abbr)
119 {
120 unsigned int i;
121 size_t tz_abbr_len = strlen(tz_abbr);
122
123 TIMELIB_TIME_FREE(tm->tz_abbr);
124 tm->tz_abbr = timelib_strdup(tz_abbr);
125 for (i = 0; i < tz_abbr_len; i++) {
126 tm->tz_abbr[i] = toupper(tz_abbr[i]);
127 }
128 }
129
timelib_time_offset_ctor(void)130 timelib_time_offset* timelib_time_offset_ctor(void)
131 {
132 timelib_time_offset *t;
133 t = timelib_calloc(1, sizeof(timelib_time_offset));
134
135 return t;
136 }
137
timelib_time_offset_dtor(timelib_time_offset * t)138 void timelib_time_offset_dtor(timelib_time_offset* t)
139 {
140 TIMELIB_TIME_FREE(t->abbr);
141 TIMELIB_TIME_FREE(t);
142 }
143
timelib_get_tz_abbr_ptr(timelib_time * t)144 char *timelib_get_tz_abbr_ptr(timelib_time *t)
145 {
146 if (!t->sse_uptodate) {
147 timelib_update_ts(t, NULL);
148 };
149 return t->tz_abbr;
150 }
151
timelib_error_container_dtor(timelib_error_container * errors)152 void timelib_error_container_dtor(timelib_error_container *errors)
153 {
154 int i;
155
156 for (i = 0; i < errors->warning_count; i++) {
157 timelib_free(errors->warning_messages[i].message);
158 }
159 timelib_free(errors->warning_messages);
160 for (i = 0; i < errors->error_count; i++) {
161 timelib_free(errors->error_messages[i].message);
162 }
163 timelib_free(errors->error_messages);
164 timelib_free(errors);
165 }
166
timelib_date_to_int(timelib_time * d,int * error)167 timelib_long timelib_date_to_int(timelib_time *d, int *error)
168 {
169 timelib_sll ts;
170
171 ts = d->sse;
172
173 if (ts < TIMELIB_LONG_MIN || ts > TIMELIB_LONG_MAX) {
174 if (error) {
175 *error = 1;
176 }
177 return 0;
178 }
179 if (error) {
180 *error = 0;
181 }
182 return (timelib_long) d->sse;
183 }
184
timelib_decimal_hour_to_hms(double h,int * hour,int * min,int * sec)185 void timelib_decimal_hour_to_hms(double h, int *hour, int *min, int *sec)
186 {
187 if (h > 0) {
188 *hour = floor(h);
189 *min = floor((h - *hour) * 60);
190 *sec = (h - *hour - ((float) *min / 60)) * 3600;
191 } else {
192 *hour = ceil(h);
193 *min = 0 - ceil((h - *hour) * 60);
194 *sec = 0 - (h - *hour - ((float) *min / -60)) * 3600;
195 }
196 }
197
timelib_hms_to_decimal_hour(int hour,int min,int sec,double * h)198 void timelib_hms_to_decimal_hour(int hour, int min, int sec, double *h)
199 {
200 if (hour > 0) {
201 *h = ((double)hour + (double)min / 60 + (double)sec / 3600);
202 } else {
203 *h = ((double)hour - (double)min / 60 - (double)sec / 3600);
204 }
205 }
206
207 static const unsigned char timelib_tolower_map[256] = {
208 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
209 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
210 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
211 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
212 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
213 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
214 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
215 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
216 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
217 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
218 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
219 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
220 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
221 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
222 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
223 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
224 };
225
226 #define timelib_tolower(c) (timelib_tolower_map[(unsigned char)(c)])
227 #undef MIN
228 #undef MAX
229 #define MAX(a, b) (((a)>(b))?(a):(b))
230 #define MIN(a, b) (((a)<(b))?(a):(b))
231
timelib_strcasecmp(const char * s1,const char * s2)232 int timelib_strcasecmp(const char *s1, const char *s2)
233 {
234 size_t len;
235 size_t len1 = strlen(s1);
236 size_t len2 = strlen(s2);
237 int c1, c2;
238
239 if (s1 == s2) {
240 return 0;
241 }
242
243 len = MIN(len1, len2);
244 while (len--) {
245 c1 = timelib_tolower(*(unsigned char *)s1++);
246 c2 = timelib_tolower(*(unsigned char *)s2++);
247 if (c1 != c2) {
248 return c1 - c2;
249 }
250 }
251
252 return (int)(len1 - len2);
253 }
254
timelib_strncasecmp(const char * s1,const char * s2,size_t length)255 int timelib_strncasecmp(const char *s1, const char *s2, size_t length)
256 {
257 size_t len;
258 size_t len1 = strlen(s1);
259 size_t len2 = strlen(s2);
260 int c1, c2;
261
262 if (s1 == s2) {
263 return 0;
264 }
265 len = MIN(length, MIN(len1, len2));
266 while (len--) {
267 c1 = timelib_tolower(*(unsigned char *)s1++);
268 c2 = timelib_tolower(*(unsigned char *)s2++);
269 if (c1 != c2) {
270 return c1 - c2;
271 }
272 }
273
274 return (int)(MIN(length, len1) - MIN(length, len2));
275 }
276
277 #undef MIN
278 #undef MAX
279
timelib_dump_date(timelib_time * d,int options)280 void timelib_dump_date(timelib_time *d, int options)
281 {
282 if ((options & 2) == 2) {
283 printf("TYPE: %d ", d->zone_type);
284 }
285 printf("TS: %lld | %s%04lld-%02lld-%02lld %02lld:%02lld:%02lld",
286 d->sse, d->y < 0 ? "-" : "", TIMELIB_LLABS(d->y), d->m, d->d, d->h, d->i, d->s);
287 if (d->us > 0) {
288 printf(" 0.%06lld", d->us);
289 }
290
291 if (d->is_localtime) {
292 switch (d->zone_type) {
293 case TIMELIB_ZONETYPE_OFFSET: /* Only offset */
294 printf(" GMT %05d%s", d->z, d->dst == 1 ? " (DST)" : "");
295 break;
296 case TIMELIB_ZONETYPE_ID: /* Timezone struct */
297 /* Show abbreviation if wanted */
298 if (d->tz_abbr) {
299 printf(" %s", d->tz_abbr);
300 }
301 /* Do we have a TimeZone struct? */
302 if (d->tz_info) {
303 printf(" %s", d->tz_info->name);
304 }
305 break;
306 case TIMELIB_ZONETYPE_ABBR:
307 printf(" %s", d->tz_abbr);
308 printf(" %05d%s", d->z, d->dst == 1 ? " (DST)" : "");
309 break;
310 }
311 }
312
313 if ((options & 1) == 1) {
314 if (d->have_relative) {
315 printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS",
316 d->relative.y, d->relative.m, d->relative.d, d->relative.h, d->relative.i, d->relative.s);
317 if (d->relative.us) {
318 printf(" 0.%06lld", d->relative.us);
319 }
320 if (d->relative.first_last_day_of != 0) {
321 switch (d->relative.first_last_day_of) {
322 case 1:
323 printf(" / first day of");
324 break;
325 case 2:
326 printf(" / last day of");
327 break;
328 }
329 }
330 if (d->relative.have_weekday_relative) {
331 printf(" / %d.%d", d->relative.weekday, d->relative.weekday_behavior);
332 }
333 if (d->relative.have_special_relative) {
334 switch (d->relative.special.type) {
335 case TIMELIB_SPECIAL_WEEKDAY:
336 printf(" / %lld weekday", d->relative.special.amount);
337 break;
338 case TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH:
339 printf(" / x y of z month");
340 break;
341 case TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH:
342 printf(" / last y of z month");
343 break;
344 }
345 }
346 }
347 }
348 printf("\n");
349 }
350
timelib_dump_rel_time(timelib_rel_time * d)351 void timelib_dump_rel_time(timelib_rel_time *d)
352 {
353 printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS (days: %lld)%s",
354 d->y, d->m, d->d, d->h, d->i, d->s, d->days, d->invert ? " inverted" : "");
355 if (d->first_last_day_of != 0) {
356 switch (d->first_last_day_of) {
357 case 1:
358 printf(" / first day of");
359 break;
360 case 2:
361 printf(" / last day of");
362 break;
363 }
364 }
365 printf("\n");
366 }
367