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