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[9] = {
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 "A 'slim' timezone file has been detected",
47 };
48
timelib_get_error_message(int error_code)49 const char *timelib_get_error_message(int error_code)
50 {
51 int entries = sizeof(timelib_error_messages) / sizeof(char*);
52
53 if (error_code >= 0 && error_code < entries) {
54 return timelib_error_messages[error_code];
55 }
56 return "Unknown error code";
57 }
58
timelib_time_ctor(void)59 timelib_time* timelib_time_ctor(void)
60 {
61 timelib_time *t;
62 t = timelib_calloc(1, sizeof(timelib_time));
63
64 return t;
65 }
66
timelib_time_dtor(timelib_time * t)67 void timelib_time_dtor(timelib_time* t)
68 {
69 TIMELIB_TIME_FREE(t->tz_abbr);
70 TIMELIB_TIME_FREE(t);
71 }
72
timelib_time_compare(timelib_time * t1,timelib_time * t2)73 int timelib_time_compare(timelib_time *t1, timelib_time *t2)
74 {
75 if (t1->sse == t2->sse) {
76 if (t1->us == t2->us) {
77 return 0;
78 }
79
80 return (t1->us < t2->us) ? -1 : 1;
81 }
82
83 return (t1->sse < t2->sse) ? -1 : 1;
84 }
85
timelib_time_clone(timelib_time * orig)86 timelib_time* timelib_time_clone(timelib_time *orig)
87 {
88 timelib_time *tmp = timelib_time_ctor();
89 memcpy(tmp, orig, sizeof(timelib_time));
90 if (orig->tz_abbr) {
91 tmp->tz_abbr = timelib_strdup(orig->tz_abbr);
92 }
93 if (orig->tz_info) {
94 tmp->tz_info = orig->tz_info;
95 }
96 return tmp;
97 }
98
timelib_rel_time_ctor(void)99 timelib_rel_time* timelib_rel_time_ctor(void)
100 {
101 timelib_rel_time *t;
102 t = timelib_calloc(1, sizeof(timelib_rel_time));
103
104 return t;
105 }
106
timelib_rel_time_dtor(timelib_rel_time * t)107 void timelib_rel_time_dtor(timelib_rel_time* t)
108 {
109 TIMELIB_TIME_FREE(t);
110 }
111
timelib_rel_time_clone(timelib_rel_time * rel)112 timelib_rel_time* timelib_rel_time_clone(timelib_rel_time *rel)
113 {
114 timelib_rel_time *tmp = timelib_rel_time_ctor();
115 memcpy(tmp, rel, sizeof(timelib_rel_time));
116 return tmp;
117 }
118
timelib_time_tz_abbr_update(timelib_time * tm,const char * tz_abbr)119 void timelib_time_tz_abbr_update(timelib_time* tm, const char* tz_abbr)
120 {
121 unsigned int i;
122 size_t tz_abbr_len = strlen(tz_abbr);
123
124 TIMELIB_TIME_FREE(tm->tz_abbr);
125 tm->tz_abbr = timelib_strdup(tz_abbr);
126 for (i = 0; i < tz_abbr_len; i++) {
127 tm->tz_abbr[i] = toupper(tz_abbr[i]);
128 }
129 }
130
timelib_time_offset_ctor(void)131 timelib_time_offset* timelib_time_offset_ctor(void)
132 {
133 timelib_time_offset *t;
134 t = timelib_calloc(1, sizeof(timelib_time_offset));
135
136 return t;
137 }
138
timelib_time_offset_dtor(timelib_time_offset * t)139 void timelib_time_offset_dtor(timelib_time_offset* t)
140 {
141 TIMELIB_TIME_FREE(t->abbr);
142 TIMELIB_TIME_FREE(t);
143 }
144
timelib_get_tz_abbr_ptr(timelib_time * t)145 char *timelib_get_tz_abbr_ptr(timelib_time *t)
146 {
147 if (!t->sse_uptodate) {
148 timelib_update_ts(t, NULL);
149 };
150 return t->tz_abbr;
151 }
152
timelib_error_container_dtor(timelib_error_container * errors)153 void timelib_error_container_dtor(timelib_error_container *errors)
154 {
155 int i;
156
157 for (i = 0; i < errors->warning_count; i++) {
158 timelib_free(errors->warning_messages[i].message);
159 }
160 timelib_free(errors->warning_messages);
161 for (i = 0; i < errors->error_count; i++) {
162 timelib_free(errors->error_messages[i].message);
163 }
164 timelib_free(errors->error_messages);
165 timelib_free(errors);
166 }
167
timelib_date_to_int(timelib_time * d,int * error)168 timelib_long timelib_date_to_int(timelib_time *d, int *error)
169 {
170 timelib_sll ts;
171
172 ts = d->sse;
173
174 if (ts < TIMELIB_LONG_MIN || ts > TIMELIB_LONG_MAX) {
175 if (error) {
176 *error = 1;
177 }
178 return 0;
179 }
180 if (error) {
181 *error = 0;
182 }
183 return (timelib_long) d->sse;
184 }
185
timelib_decimal_hour_to_hms(double h,int * hour,int * min,int * sec)186 void timelib_decimal_hour_to_hms(double h, int *hour, int *min, int *sec)
187 {
188 if (h > 0) {
189 *hour = floor(h);
190 *min = floor((h - *hour) * 60);
191 *sec = (h - *hour - ((float) *min / 60)) * 3600;
192 } else {
193 *hour = ceil(h);
194 *min = 0 - ceil((h - *hour) * 60);
195 *sec = 0 - (h - *hour - ((float) *min / -60)) * 3600;
196 }
197 }
198
timelib_hms_to_decimal_hour(int hour,int min,int sec,double * h)199 void timelib_hms_to_decimal_hour(int hour, int min, int sec, double *h)
200 {
201 if (hour > 0) {
202 *h = ((double)hour + (double)min / 60 + (double)sec / 3600);
203 } else {
204 *h = ((double)hour - (double)min / 60 - (double)sec / 3600);
205 }
206 }
207
208 static const unsigned char timelib_tolower_map[256] = {
209 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
210 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
211 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
212 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
213 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
214 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
215 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
216 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
217 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
218 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
219 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
220 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
221 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
222 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
223 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
224 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
225 };
226
227 #define timelib_tolower(c) (timelib_tolower_map[(unsigned char)(c)])
228 #undef MIN
229 #undef MAX
230 #define MAX(a, b) (((a)>(b))?(a):(b))
231 #define MIN(a, b) (((a)<(b))?(a):(b))
232
timelib_strcasecmp(const char * s1,const char * s2)233 int timelib_strcasecmp(const char *s1, const char *s2)
234 {
235 size_t len;
236 size_t len1 = strlen(s1);
237 size_t len2 = strlen(s2);
238 int c1, c2;
239
240 if (s1 == s2) {
241 return 0;
242 }
243
244 len = MIN(len1, len2);
245 while (len--) {
246 c1 = timelib_tolower(*(unsigned char *)s1++);
247 c2 = timelib_tolower(*(unsigned char *)s2++);
248 if (c1 != c2) {
249 return c1 - c2;
250 }
251 }
252
253 return (int)(len1 - len2);
254 }
255
timelib_strncasecmp(const char * s1,const char * s2,size_t length)256 int timelib_strncasecmp(const char *s1, const char *s2, size_t length)
257 {
258 size_t len;
259 size_t len1 = strlen(s1);
260 size_t len2 = strlen(s2);
261 int c1, c2;
262
263 if (s1 == s2) {
264 return 0;
265 }
266 len = MIN(length, MIN(len1, len2));
267 while (len--) {
268 c1 = timelib_tolower(*(unsigned char *)s1++);
269 c2 = timelib_tolower(*(unsigned char *)s2++);
270 if (c1 != c2) {
271 return c1 - c2;
272 }
273 }
274
275 return (int)(MIN(length, len1) - MIN(length, len2));
276 }
277
278 #undef MIN
279 #undef MAX
280
timelib_dump_date(timelib_time * d,int options)281 void timelib_dump_date(timelib_time *d, int options)
282 {
283 if ((options & 2) == 2) {
284 printf("TYPE: %d ", d->zone_type);
285 }
286 printf("TS: %lld | %s%04lld-%02lld-%02lld %02lld:%02lld:%02lld",
287 d->sse, d->y < 0 ? "-" : "", TIMELIB_LLABS(d->y), d->m, d->d, d->h, d->i, d->s);
288 if (d->us > 0) {
289 printf(" 0.%06lld", d->us);
290 }
291
292 if (d->is_localtime) {
293 switch (d->zone_type) {
294 case TIMELIB_ZONETYPE_OFFSET: /* Only offset */
295 printf(" GMT %05d%s", d->z, d->dst == 1 ? " (DST)" : "");
296 break;
297 case TIMELIB_ZONETYPE_ID: /* Timezone struct */
298 /* Show abbreviation if wanted */
299 if (d->tz_abbr) {
300 printf(" %s", d->tz_abbr);
301 }
302 /* Do we have a TimeZone struct? */
303 if (d->tz_info) {
304 printf(" %s", d->tz_info->name);
305 }
306 break;
307 case TIMELIB_ZONETYPE_ABBR:
308 printf(" %s", d->tz_abbr);
309 printf(" %05d%s", d->z, d->dst == 1 ? " (DST)" : "");
310 break;
311 }
312 }
313
314 if ((options & 1) == 1) {
315 if (d->have_relative) {
316 printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS",
317 d->relative.y, d->relative.m, d->relative.d, d->relative.h, d->relative.i, d->relative.s);
318 if (d->relative.us) {
319 printf(" 0.%06lld", d->relative.us);
320 }
321 if (d->relative.first_last_day_of != 0) {
322 switch (d->relative.first_last_day_of) {
323 case 1:
324 printf(" / first day of");
325 break;
326 case 2:
327 printf(" / last day of");
328 break;
329 }
330 }
331 if (d->relative.have_weekday_relative) {
332 printf(" / %d.%d", d->relative.weekday, d->relative.weekday_behavior);
333 }
334 if (d->relative.have_special_relative) {
335 switch (d->relative.special.type) {
336 case TIMELIB_SPECIAL_WEEKDAY:
337 printf(" / %lld weekday", d->relative.special.amount);
338 break;
339 case TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH:
340 printf(" / x y of z month");
341 break;
342 case TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH:
343 printf(" / last y of z month");
344 break;
345 }
346 }
347 }
348 }
349 printf("\n");
350 }
351
timelib_dump_rel_time(timelib_rel_time * d)352 void timelib_dump_rel_time(timelib_rel_time *d)
353 {
354 printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS (days: %lld)%s",
355 d->y, d->m, d->d, d->h, d->i, d->s, d->days, d->invert ? " inverted" : "");
356 if (d->first_last_day_of != 0) {
357 switch (d->first_last_day_of) {
358 case 1:
359 printf(" / first day of");
360 break;
361 case 2:
362 printf(" / last day of");
363 break;
364 }
365 }
366 printf("\n");
367 }
368