Coverage Report

Created: 2025-12-14 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/date/lib/timelib.c
Line
Count
Source
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
0
#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
51
const char *timelib_get_error_message(int error_code)
52
0
{
53
0
  int entries = sizeof(timelib_error_messages) / sizeof(char*);
54
55
0
  if (error_code >= 0 && error_code < entries) {
56
0
    return timelib_error_messages[error_code];
57
0
  }
58
0
  return "Unknown error code";
59
0
}
60
61
timelib_time* timelib_time_ctor(void)
62
1.37k
{
63
1.37k
  timelib_time *t;
64
1.37k
  t = timelib_calloc(1, sizeof(timelib_time));
65
66
1.37k
  return t;
67
1.37k
}
68
69
void timelib_time_dtor(timelib_time* t)
70
1.37k
{
71
1.37k
  TIMELIB_TIME_FREE(t->tz_abbr);
72
1.37k
  TIMELIB_TIME_FREE(t);
73
1.37k
}
74
75
int timelib_time_compare(timelib_time *t1, timelib_time *t2)
76
0
{
77
0
  if (t1->sse == t2->sse) {
78
0
    if (t1->us == t2->us) {
79
0
      return 0;
80
0
    }
81
82
0
    return (t1->us < t2->us) ? -1 : 1;
83
0
  }
84
85
0
  return (t1->sse < t2->sse) ? -1 : 1;
86
0
}
87
88
timelib_time* timelib_time_clone(timelib_time *orig)
89
0
{
90
0
  timelib_time *tmp = timelib_time_ctor();
91
0
  memcpy(tmp, orig, sizeof(timelib_time));
92
0
  if (orig->tz_abbr) {
93
0
    tmp->tz_abbr = timelib_strdup(orig->tz_abbr);
94
0
  }
95
0
  if (orig->tz_info) {
96
0
    tmp->tz_info = orig->tz_info;
97
0
  }
98
0
  return tmp;
99
0
}
100
101
timelib_rel_time* timelib_rel_time_ctor(void)
102
1
{
103
1
  timelib_rel_time *t;
104
1
  t = timelib_calloc(1, sizeof(timelib_rel_time));
105
106
1
  return t;
107
1
}
108
109
void timelib_rel_time_dtor(timelib_rel_time* t)
110
10
{
111
10
  TIMELIB_TIME_FREE(t);
112
10
}
113
114
timelib_rel_time* timelib_rel_time_clone(timelib_rel_time *rel)
115
0
{
116
0
  timelib_rel_time *tmp = timelib_rel_time_ctor();
117
0
  memcpy(tmp, rel, sizeof(timelib_rel_time));
118
0
  return tmp;
119
0
}
120
121
void timelib_time_tz_abbr_update(timelib_time* tm, const char* tz_abbr)
122
572
{
123
572
  unsigned int i;
124
572
  size_t tz_abbr_len = strlen(tz_abbr);
125
126
572
  TIMELIB_TIME_FREE(tm->tz_abbr);
127
572
  tm->tz_abbr = timelib_strdup(tz_abbr);
128
1.35k
  for (i = 0; i < tz_abbr_len; i++) {
129
787
    tm->tz_abbr[i] = toupper(tz_abbr[i]);
130
787
  }
131
572
}
132
133
timelib_time_offset* timelib_time_offset_ctor(void)
134
161
{
135
161
  timelib_time_offset *t;
136
161
  t = timelib_calloc(1, sizeof(timelib_time_offset));
137
138
161
  return t;
139
161
}
140
141
void timelib_time_offset_dtor(timelib_time_offset* t)
142
161
{
143
161
  TIMELIB_TIME_FREE(t->abbr);
144
161
  TIMELIB_TIME_FREE(t);
145
161
}
146
147
char *timelib_get_tz_abbr_ptr(timelib_time *t)
148
0
{
149
0
  if (!t->sse_uptodate) {
150
0
    timelib_update_ts(t, NULL);
151
0
  };
152
0
  return t->tz_abbr;
153
0
}
154
155
void timelib_error_container_dtor(timelib_error_container *errors)
156
1.26k
{
157
1.26k
  int i;
158
159
2.71k
  for (i = 0; i < errors->warning_count; i++) {
160
1.45k
    timelib_free(errors->warning_messages[i].message);
161
1.45k
  }
162
1.26k
  timelib_free(errors->warning_messages);
163
52.9k
  for (i = 0; i < errors->error_count; i++) {
164
51.6k
    timelib_free(errors->error_messages[i].message);
165
51.6k
  }
166
1.26k
  timelib_free(errors->error_messages);
167
1.26k
  timelib_free(errors);
168
1.26k
}
169
170
timelib_long timelib_date_to_int(timelib_time *d, int *error)
171
1
{
172
1
  timelib_sll ts;
173
174
1
  ts = d->sse;
175
176
1
  if (ts < TIMELIB_LONG_MIN || ts > TIMELIB_LONG_MAX) {
177
0
    if (error) {
178
0
      *error = 1;
179
0
    }
180
0
    return 0;
181
0
  }
182
1
  if (error) {
183
1
    *error = 0;
184
1
  }
185
1
  return (timelib_long) d->sse;
186
1
}
187
188
void timelib_decimal_hour_to_hms(double h, int *hour, int *min, int *sec)
189
0
{
190
0
  bool swap = false;
191
0
  int seconds;
192
193
0
  if (h < 0) {
194
0
    swap = true;
195
0
    h = fabs(h);
196
0
  }
197
198
0
  *hour = floor(h);
199
0
  seconds = floor((h - *hour) * 3600);
200
201
0
  *min = seconds / 60;
202
0
  *sec = seconds % 60;
203
204
0
  if (swap) {
205
0
    *hour = 0 - *hour;
206
0
  }
207
0
}
208
209
void timelib_hms_to_decimal_hour(int hour, int min, int sec, double *h)
210
0
{
211
0
  if (hour >= 0) {
212
0
    *h = ((double)hour + (double)min / 60 + (double)sec / 3600);
213
0
  } else {
214
0
    *h = ((double)hour - (double)min / 60 - (double)sec / 3600);
215
0
  }
216
0
}
217
218
void timelib_hmsf_to_decimal_hour(int hour, int min, int sec, int us, double *h)
219
0
{
220
0
  if (hour >= 0) {
221
0
    *h = ((double)hour + (double)min / MINS_PER_HOUR + (double)sec / SECS_PER_HOUR) + (double)us / USECS_PER_HOUR;
222
0
  } else {
223
0
    *h = ((double)hour - (double)min / MINS_PER_HOUR - (double)sec / SECS_PER_HOUR) - (double)us / USECS_PER_HOUR;
224
0
  }
225
0
}
226
227
timelib_sll timelib_hms_to_seconds(timelib_sll h, timelib_sll m, timelib_sll s)
228
21
{
229
21
  return (h * SECS_PER_HOUR) + (m * 60) + s;
230
21
}
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
2.13M
#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
1.04M
#define MIN(a, b)  (((a)<(b))?(a):(b))
256
257
int timelib_strcasecmp(const char *s1, const char *s2)
258
1.04M
{
259
1.04M
  size_t len;
260
1.04M
  size_t len1 = strlen(s1);
261
1.04M
  size_t len2 = strlen(s2);
262
1.04M
  int c1, c2;
263
264
1.04M
  if (s1 == s2) {
265
0
    return 0;
266
0
  }
267
268
1.04M
  len = MIN(len1, len2);
269
1.09M
  while (len--) {
270
1.06M
    c1 = timelib_tolower(*(unsigned char *)s1++);
271
1.06M
    c2 = timelib_tolower(*(unsigned char *)s2++);
272
1.06M
    if (c1 != c2) {
273
1.02M
      return c1 - c2;
274
1.02M
    }
275
1.06M
  }
276
277
24.7k
  return (int)(len1 - len2);
278
1.04M
}
279
280
int timelib_strncasecmp(const char *s1, const char *s2, size_t length)
281
251
{
282
251
  size_t len;
283
251
  size_t len1 = strlen(s1);
284
251
  size_t len2 = strlen(s2);
285
251
  int c1, c2;
286
287
251
  if (s1 == s2) {
288
0
    return 0;
289
0
  }
290
251
  len = MIN(length, MIN(len1, len2));
291
254
  while (len--) {
292
253
    c1 = timelib_tolower(*(unsigned char *)s1++);
293
253
    c2 = timelib_tolower(*(unsigned char *)s2++);
294
253
    if (c1 != c2) {
295
250
      return c1 - c2;
296
250
    }
297
253
  }
298
299
1
  return (int)(MIN(length, len1) - MIN(length, len2));
300
251
}
301
302
#undef MIN
303
#undef MAX
304
305
void timelib_dump_date(timelib_time *d, int options)
306
0
{
307
0
  if ((options & 2) == 2) {
308
0
    printf("TYPE: %d ", d->zone_type);
309
0
  }
310
0
  printf("TS: %lld | %s%04lld-%02lld-%02lld %02lld:%02lld:%02lld",
311
0
    d->sse, d->y < 0 ? "-" : "", TIMELIB_LLABS(d->y), d->m, d->d, d->h, d->i, d->s);
312
0
  if (d->us > 0) {
313
0
    printf(" 0.%06lld", d->us);
314
0
  }
315
316
0
  if (d->is_localtime) {
317
0
    switch (d->zone_type) {
318
0
      case TIMELIB_ZONETYPE_OFFSET: /* Only offset */
319
0
        printf(" GMT %05d%s", d->z, d->dst == 1 ? " (DST)" : "");
320
0
        break;
321
0
      case TIMELIB_ZONETYPE_ID: /* Timezone struct */
322
        /* Show abbreviation if wanted */
323
0
        if (d->tz_abbr) {
324
0
          printf(" %s", d->tz_abbr);
325
0
        }
326
        /* Do we have a TimeZone struct? */
327
0
        if (d->tz_info) {
328
0
          printf(" %s", d->tz_info->name);
329
0
        }
330
0
        break;
331
0
      case TIMELIB_ZONETYPE_ABBR:
332
0
        printf(" %s", d->tz_abbr);
333
0
        printf(" %05d%s", d->z, d->dst == 1 ? " (DST)" : "");
334
0
        break;
335
0
    }
336
0
  }
337
338
0
  if ((options & 1) == 1) {
339
0
    if (d->have_relative) {
340
0
      printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS",
341
0
        d->relative.y, d->relative.m, d->relative.d, d->relative.h, d->relative.i, d->relative.s);
342
0
      if (d->relative.us) {
343
0
        printf(" 0.%06lld", d->relative.us);
344
0
      }
345
0
      if (d->relative.first_last_day_of != 0) {
346
0
        switch (d->relative.first_last_day_of) {
347
0
          case 1:
348
0
            printf(" / first day of");
349
0
            break;
350
0
          case 2:
351
0
            printf(" / last day of");
352
0
            break;
353
0
        }
354
0
      }
355
0
      if (d->relative.have_weekday_relative) {
356
0
        printf(" / %d.%d", d->relative.weekday, d->relative.weekday_behavior);
357
0
      }
358
0
      if (d->relative.have_special_relative) {
359
0
        switch (d->relative.special.type) {
360
0
          case TIMELIB_SPECIAL_WEEKDAY:
361
0
            printf(" / %lld weekday", d->relative.special.amount);
362
0
            break;
363
0
          case TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH:
364
0
            printf(" / x y of z month");
365
0
            break;
366
0
          case TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH:
367
0
            printf(" / last y of z month");
368
0
            break;
369
0
        }
370
0
      }
371
0
    }
372
0
  }
373
0
  printf("\n");
374
0
}
375
376
void timelib_dump_rel_time(timelib_rel_time *d)
377
0
{
378
0
  printf("%3lldY %3lldM %3lldD / %3lldH %3lldM %3lldS (days: %lld)%s",
379
0
    d->y, d->m, d->d, d->h, d->i, d->s, d->days, d->invert ? " inverted" : "");
380
0
  if (d->first_last_day_of != 0) {
381
0
    switch (d->first_last_day_of) {
382
0
      case 1:
383
0
        printf(" / first day of");
384
0
        break;
385
0
      case 2:
386
0
        printf(" / last day of");
387
0
        break;
388
0
    }
389
0
  }
390
0
  printf("\n");
391
0
}