Coverage Report

Created: 2025-12-14 06:09

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
170k
{
63
170k
  timelib_time *t;
64
170k
  t = timelib_calloc(1, sizeof(timelib_time));
65
66
170k
  return t;
67
170k
}
68
69
void timelib_time_dtor(timelib_time* t)
70
170k
{
71
170k
  TIMELIB_TIME_FREE(t->tz_abbr);
72
170k
  TIMELIB_TIME_FREE(t);
73
170k
}
74
75
int timelib_time_compare(timelib_time *t1, timelib_time *t2)
76
3
{
77
3
  if (t1->sse == t2->sse) {
78
3
    if (t1->us == t2->us) {
79
0
      return 0;
80
0
    }
81
82
3
    return (t1->us < t2->us) ? -1 : 1;
83
3
  }
84
85
0
  return (t1->sse < t2->sse) ? -1 : 1;
86
3
}
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
27
{
103
27
  timelib_rel_time *t;
104
27
  t = timelib_calloc(1, sizeof(timelib_rel_time));
105
106
27
  return t;
107
27
}
108
109
void timelib_rel_time_dtor(timelib_rel_time* t)
110
70
{
111
70
  TIMELIB_TIME_FREE(t);
112
70
}
113
114
timelib_rel_time* timelib_rel_time_clone(timelib_rel_time *rel)
115
6
{
116
6
  timelib_rel_time *tmp = timelib_rel_time_ctor();
117
6
  memcpy(tmp, rel, sizeof(timelib_rel_time));
118
6
  return tmp;
119
6
}
120
121
void timelib_time_tz_abbr_update(timelib_time* tm, const char* tz_abbr)
122
114k
{
123
114k
  unsigned int i;
124
114k
  size_t tz_abbr_len = strlen(tz_abbr);
125
126
114k
  TIMELIB_TIME_FREE(tm->tz_abbr);
127
114k
  tm->tz_abbr = timelib_strdup(tz_abbr);
128
292k
  for (i = 0; i < tz_abbr_len; i++) {
129
178k
    tm->tz_abbr[i] = toupper(tz_abbr[i]);
130
178k
  }
131
114k
}
132
133
timelib_time_offset* timelib_time_offset_ctor(void)
134
2.41k
{
135
2.41k
  timelib_time_offset *t;
136
2.41k
  t = timelib_calloc(1, sizeof(timelib_time_offset));
137
138
2.41k
  return t;
139
2.41k
}
140
141
void timelib_time_offset_dtor(timelib_time_offset* t)
142
2.41k
{
143
2.41k
  TIMELIB_TIME_FREE(t->abbr);
144
2.41k
  TIMELIB_TIME_FREE(t);
145
2.41k
}
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
168k
{
157
168k
  int i;
158
159
404k
  for (i = 0; i < errors->warning_count; i++) {
160
236k
    timelib_free(errors->warning_messages[i].message);
161
236k
  }
162
168k
  timelib_free(errors->warning_messages);
163
340M
  for (i = 0; i < errors->error_count; i++) {
164
340M
    timelib_free(errors->error_messages[i].message);
165
340M
  }
166
168k
  timelib_free(errors->error_messages);
167
168k
  timelib_free(errors);
168
168k
}
169
170
timelib_long timelib_date_to_int(timelib_time *d, int *error)
171
6
{
172
6
  timelib_sll ts;
173
174
6
  ts = d->sse;
175
176
6
  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
6
  if (error) {
183
6
    *error = 0;
184
6
  }
185
6
  return (timelib_long) d->sse;
186
6
}
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
6
{
220
6
  if (hour >= 0) {
221
6
    *h = ((double)hour + (double)min / MINS_PER_HOUR + (double)sec / SECS_PER_HOUR) + (double)us / USECS_PER_HOUR;
222
6
  } else {
223
0
    *h = ((double)hour - (double)min / MINS_PER_HOUR - (double)sec / SECS_PER_HOUR) - (double)us / USECS_PER_HOUR;
224
0
  }
225
6
}
226
227
timelib_sll timelib_hms_to_seconds(timelib_sll h, timelib_sll m, timelib_sll s)
228
146
{
229
146
  return (h * SECS_PER_HOUR) + (m * 60) + s;
230
146
}
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
374M
#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
182M
#define MIN(a, b)  (((a)<(b))?(a):(b))
256
257
int timelib_strcasecmp(const char *s1, const char *s2)
258
182M
{
259
182M
  size_t len;
260
182M
  size_t len1 = strlen(s1);
261
182M
  size_t len2 = strlen(s2);
262
182M
  int c1, c2;
263
264
182M
  if (s1 == s2) {
265
0
    return 0;
266
0
  }
267
268
182M
  len = MIN(len1, len2);
269
192M
  while (len--) {
270
187M
    c1 = timelib_tolower(*(unsigned char *)s1++);
271
187M
    c2 = timelib_tolower(*(unsigned char *)s2++);
272
187M
    if (c1 != c2) {
273
176M
      return c1 - c2;
274
176M
    }
275
187M
  }
276
277
5.60M
  return (int)(len1 - len2);
278
182M
}
279
280
int timelib_strncasecmp(const char *s1, const char *s2, size_t length)
281
283k
{
282
283k
  size_t len;
283
283k
  size_t len1 = strlen(s1);
284
283k
  size_t len2 = strlen(s2);
285
283k
  int c1, c2;
286
287
283k
  if (s1 == s2) {
288
0
    return 0;
289
0
  }
290
283k
  len = MIN(length, MIN(len1, len2));
291
284k
  while (len--) {
292
284k
    c1 = timelib_tolower(*(unsigned char *)s1++);
293
284k
    c2 = timelib_tolower(*(unsigned char *)s2++);
294
284k
    if (c1 != c2) {
295
283k
      return c1 - c2;
296
283k
    }
297
284k
  }
298
299
171
  return (int)(MIN(length, len1) - MIN(length, len2));
300
283k
}
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
}