Coverage Report

Created: 2025-07-11 06:13

/src/libxslt/libexslt/date.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * date.c: Implementation of the EXSLT -- Dates and Times module
3
 *
4
 * References:
5
 *   http://www.exslt.org/date/date.html
6
 *
7
 * See Copyright for the status of this software.
8
 *
9
 * Authors:
10
 *   Charlie Bozeman <cbozeman@HiWAAY.net>
11
 *   Thomas Broyer <tbroyer@ltgt.net>
12
 *
13
 * TODO:
14
 * elements:
15
 *   date-format
16
 * functions:
17
 *   format-date
18
 *   parse-date
19
 *   sum
20
 */
21
22
#define IN_LIBEXSLT
23
#include "libexslt/libexslt.h"
24
25
#if defined(HAVE_LOCALTIME_R) && defined(__GLIBC__) /* _POSIX_SOURCE required by gnu libc */
26
#ifndef _AIX51    /* but on AIX we're not using gnu libc */
27
#define _POSIX_SOURCE
28
#endif
29
#endif
30
31
#include <libxml/tree.h>
32
#include <libxml/xpath.h>
33
#include <libxml/xpathInternals.h>
34
35
#include <libxslt/xsltutils.h>
36
#include <libxslt/xsltInternals.h>
37
#include <libxslt/extensions.h>
38
39
#include "exslt.h"
40
41
#include <stdlib.h>
42
#include <string.h>
43
#include <limits.h>
44
#include <errno.h>
45
#include <math.h>
46
47
/* needed to get localtime_r on Solaris */
48
#ifdef __sun
49
#ifndef __EXTENSIONS__
50
#define __EXTENSIONS__
51
#endif
52
#endif
53
54
#include <time.h>
55
56
#if defined(_MSC_VER) && _MSC_VER >= 1400 || \
57
    defined(_WIN32) && \
58
    defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR >= 4
59
  #define HAVE_MSVCRT
60
#endif
61
62
/*
63
 * types of date and/or time (from schema datatypes)
64
 *   somewhat ordered from least specific to most specific (i.e.
65
 *   most truncated to least truncated).
66
 */
67
typedef enum {
68
    EXSLT_UNKNOWN  =    0,
69
    XS_TIME        =    1,       /* time is left-truncated */
70
    XS_GDAY        = (XS_TIME   << 1),
71
    XS_GMONTH      = (XS_GDAY   << 1),
72
    XS_GMONTHDAY   = (XS_GMONTH | XS_GDAY),
73
    XS_GYEAR       = (XS_GMONTH << 1),
74
    XS_GYEARMONTH  = (XS_GYEAR  | XS_GMONTH),
75
    XS_DATE        = (XS_GYEAR  | XS_GMONTH | XS_GDAY),
76
    XS_DATETIME    = (XS_DATE   | XS_TIME)
77
} exsltDateType;
78
79
/* Date value */
80
typedef struct _exsltDateVal exsltDateVal;
81
typedef exsltDateVal *exsltDateValPtr;
82
struct _exsltDateVal {
83
    exsltDateType type;
84
    long    year;
85
    unsigned int  mon :4; /* 1 <=  mon    <= 12   */
86
    unsigned int  day :5; /* 1 <=  day    <= 31   */
87
    unsigned int  hour  :5; /* 0 <=  hour   <= 23   */
88
    unsigned int  min :6; /* 0 <=  min    <= 59 */
89
    double    sec;
90
    unsigned int  tz_flag :1; /* is tzo explicitely set? */
91
    signed int    tzo :12;  /* -1440 <= tzo <= 1440 currently only -840 to +840 are needed */
92
};
93
94
/* Duration value */
95
typedef struct _exsltDateDurVal exsltDateDurVal;
96
typedef exsltDateDurVal *exsltDateDurValPtr;
97
struct _exsltDateDurVal {
98
    long  mon;  /* mon stores years also */
99
    long  day;
100
    double  sec;  /* sec stores min and hour also
101
         0 <= sec < SECS_PER_DAY */
102
};
103
104
/****************************************************************
105
 *                *
106
 *    Convenience macros and functions    *
107
 *                *
108
 ****************************************************************/
109
110
#define IS_TZO_CHAR(c)            \
111
393k
  ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
112
113
71.4k
#define VALID_ALWAYS(num) (num >= 0)
114
479k
#define VALID_MONTH(mon)        ((mon >= 1) && (mon <= 12))
115
/* VALID_DAY should only be used when month is unknown */
116
115k
#define VALID_DAY(day)          ((day >= 1) && (day <= 31))
117
452k
#define VALID_HOUR(hr)          ((hr >= 0) && (hr <= 23))
118
102k
#define VALID_MIN(min)          ((min >= 0) && (min <= 59))
119
274k
#define VALID_SEC(sec)          ((sec >= 0) && (sec < 60))
120
158k
#define VALID_TZO(tzo)          ((tzo > -1440) && (tzo < 1440))
121
#define IS_LEAP(y)            \
122
2.33M
  (((y & 3) == 0) && ((y % 25 != 0) || ((y & 15) == 0)))
123
124
static const long daysInMonth[12] =
125
  { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
126
static const long daysInMonthLeap[12] =
127
  { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
128
129
#define MAX_DAYINMONTH(yr,mon)                                  \
130
2.11M
        (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
131
132
#define VALID_MDAY(dt)            \
133
169k
  (IS_LEAP(dt->year) ?                \
134
169k
      (dt->day <= daysInMonthLeap[dt->mon - 1]) :          \
135
169k
      (dt->day <= daysInMonth[dt->mon - 1]))
136
137
#define VALID_DATE(dt)            \
138
232k
  (VALID_MONTH(dt->mon) && VALID_MDAY(dt))
139
140
/*
141
    hour and min structure vals are unsigned, so normal macros give
142
    warnings on some compilers.
143
*/
144
#define VALID_TIME(dt)            \
145
137k
  ((dt->hour <=23 ) && (dt->min <= 59) &&     \
146
137k
   VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
147
148
#define VALID_DATETIME(dt)          \
149
62.5k
  (VALID_DATE(dt) && VALID_TIME(dt))
150
151
144k
#define SECS_PER_MIN            60
152
125k
#define MINS_PER_HOUR           60
153
106k
#define HOURS_PER_DAY           24
154
116k
#define SECS_PER_HOUR           (MINS_PER_HOUR * SECS_PER_MIN)
155
93.4k
#define SECS_PER_DAY            (HOURS_PER_DAY * SECS_PER_HOUR)
156
9.06k
#define MINS_PER_DAY            (HOURS_PER_DAY * MINS_PER_HOUR)
157
15.8k
#define DAYS_PER_EPOCH          (400 * 365 + 100 - 4 + 1)
158
8.00k
#define YEARS_PER_EPOCH         400
159
160
static const long dayInYearByMonth[12] =
161
  { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
162
static const long dayInLeapYearByMonth[12] =
163
  { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
164
165
#define DAY_IN_YEAR(day, month, year)       \
166
46.6k
        ((IS_LEAP(year) ?          \
167
46.6k
                dayInLeapYearByMonth[month - 1] :    \
168
46.6k
                dayInYearByMonth[month - 1]) + day)
169
170
801k
#define YEAR_MAX LONG_MAX
171
16.8k
#define YEAR_MIN (-LONG_MAX + 1)
172
173
/**
174
 * _exsltDateParseGYear:
175
 * @dt:  pointer to a date structure
176
 * @str: pointer to the string to analyze
177
 *
178
 * Parses a xs:gYear without time zone and fills in the appropriate
179
 * field of the @dt structure. @str is updated to point just after the
180
 * xs:gYear. It is supposed that @dt->year is big enough to contain
181
 * the year.
182
 *
183
 * According to XML Schema Part 2, the year "0000" is an illegal year value
184
 * which probably means that the year preceding AD 1 is BC 1. Internally,
185
 * we allow a year 0 and adjust the value when parsing and formatting.
186
 *
187
 * Returns 0 or the error code
188
 */
189
static int
190
_exsltDateParseGYear (exsltDateValPtr dt, const xmlChar **str)
191
181k
{
192
181k
    const xmlChar *cur = *str, *firstChar;
193
181k
    int isneg = 0, digcnt = 0;
194
195
181k
    if (((*cur < '0') || (*cur > '9')) &&
196
181k
  (*cur != '-') && (*cur != '+'))
197
21.1k
  return -1;
198
199
160k
    if (*cur == '-') {
200
42.6k
  isneg = 1;
201
42.6k
  cur++;
202
42.6k
    }
203
204
160k
    firstChar = cur;
205
206
877k
    while ((*cur >= '0') && (*cur <= '9')) {
207
719k
        if (dt->year >= YEAR_MAX / 10) /* Not really exact */
208
1.36k
            return -1;
209
717k
  dt->year = dt->year * 10 + (*cur - '0');
210
717k
  cur++;
211
717k
  digcnt++;
212
717k
    }
213
214
    /* year must be at least 4 digits (CCYY); over 4
215
     * digits cannot have a leading zero. */
216
158k
    if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
217
14.0k
  return 1;
218
219
144k
    if (dt->year == 0)
220
1.60k
  return 2;
221
222
    /* The internal representation of negative years is continuous. */
223
143k
    if (isneg)
224
40.3k
  dt->year = -dt->year + 1;
225
226
143k
    *str = cur;
227
228
#ifdef DEBUG_EXSLT_DATE
229
    xsltGenericDebug(xsltGenericDebugContext,
230
         "Parsed year %04ld\n", dt->year);
231
#endif
232
233
143k
    return 0;
234
144k
}
235
236
/**
237
 * exsltFormatGYear:
238
 * @cur: a pointer to a pointer to an allocated buffer
239
 * @end: a pointer to the end of @cur buffer
240
 * @yr:  the year to format
241
 *
242
 * Formats @yr in xsl:gYear format. Result is appended to @cur and
243
 * @cur is updated to point after the xsl:gYear.
244
 */
245
static void
246
exsltFormatGYear(xmlChar **cur, xmlChar *end, long yr)
247
9.29k
{
248
9.29k
    long year;
249
9.29k
    xmlChar tmp_buf[100], *tmp = tmp_buf, *tmp_end = tmp_buf + 99;
250
251
9.29k
    if (yr <= 0 && *cur < end) {
252
1.87k
        *(*cur)++ = '-';
253
1.87k
    }
254
255
9.29k
    year = (yr <= 0) ? -yr + 1 : yr;
256
    /* result is in reverse-order */
257
45.9k
    while (year > 0 && tmp < tmp_end) {
258
36.6k
        *tmp++ = '0' + (xmlChar)(year % 10);
259
36.6k
        year /= 10;
260
36.6k
    }
261
262
    /* virtually adds leading zeros */
263
18.6k
    while ((tmp - tmp_buf) < 4)
264
9.31k
        *tmp++ = '0';
265
266
    /* restore the correct order */
267
55.2k
    while (tmp > tmp_buf && *cur < end) {
268
45.9k
        tmp--;
269
45.9k
        *(*cur)++ = *tmp;
270
45.9k
    }
271
9.29k
}
272
273
/**
274
 * PARSE_2_DIGITS:
275
 * @num:  the integer to fill in
276
 * @cur:  an #xmlChar *
277
 * @func: validation function for the number
278
 * @invalid: an integer
279
 *
280
 * Parses a 2-digits integer and updates @num with the value. @cur is
281
 * updated to point just after the integer.
282
 * In case of error, @invalid is set to %TRUE, values of @num and
283
 * @cur are undefined.
284
 */
285
#define PARSE_2_DIGITS(num, cur, func, invalid)     \
286
923k
  if ((cur[0] < '0') || (cur[0] > '9') ||     \
287
923k
      (cur[1] < '0') || (cur[1] > '9'))     \
288
923k
      invalid = 1;         \
289
923k
  else {             \
290
880k
      int val;            \
291
880k
      val = (cur[0] - '0') * 10 + (cur[1] - '0');   \
292
880k
      if (!func(val))          \
293
880k
          invalid = 2;         \
294
880k
      else            \
295
880k
          num = val;         \
296
880k
  }              \
297
923k
  cur += 2;
298
299
/**
300
 * exsltFormat2Digits:
301
 * @cur: a pointer to a pointer to an allocated buffer
302
 * @end: a pointer to the end of @cur buffer
303
 * @num: the integer to format
304
 *
305
 * Formats a 2-digits integer. Result is appended to @cur and
306
 * @cur is updated to point after the integer.
307
 */
308
static void
309
exsltFormat2Digits(xmlChar **cur, xmlChar *end, unsigned int num)
310
23.4k
{
311
23.4k
    if (*cur < end)
312
23.4k
        *(*cur)++ = '0' + ((num / 10) % 10);
313
23.4k
    if (*cur < end)
314
23.4k
        *(*cur)++ = '0' + (num % 10);
315
23.4k
}
316
317
/**
318
 * PARSE_FLOAT:
319
 * @num:  the double to fill in
320
 * @cur:  an #xmlChar *
321
 * @invalid: an integer
322
 *
323
 * Parses a float and updates @num with the value. @cur is
324
 * updated to point just after the float. The float must have a
325
 * 2-digits integer part and may or may not have a decimal part.
326
 * In case of error, @invalid is set to %TRUE, values of @num and
327
 * @cur are undefined.
328
 */
329
#define PARSE_FLOAT(num, cur, invalid)        \
330
74.8k
  PARSE_2_DIGITS(num, cur, VALID_ALWAYS, invalid); \
331
74.8k
  if (!invalid && (*cur == '.')) {     \
332
19.5k
      double mult = 1;                \
333
19.5k
      cur++;            \
334
19.5k
      if ((*cur < '0') || (*cur > '9'))     \
335
19.5k
    invalid = 1;         \
336
102k
      while ((*cur >= '0') && (*cur <= '9')) {   \
337
82.9k
    mult /= 10;         \
338
82.9k
    num += (*cur - '0') * mult;     \
339
82.9k
    cur++;            \
340
82.9k
      }              \
341
19.5k
  }
342
343
/**
344
 * _exsltDateParseGMonth:
345
 * @dt:  pointer to a date structure
346
 * @str: pointer to the string to analyze
347
 *
348
 * Parses a xs:gMonth without time zone and fills in the appropriate
349
 * field of the @dt structure. @str is updated to point just after the
350
 * xs:gMonth.
351
 *
352
 * Returns 0 or the error code
353
 */
354
static int
355
_exsltDateParseGMonth (exsltDateValPtr dt, const xmlChar **str)
356
147k
{
357
147k
    const xmlChar *cur = *str;
358
147k
    int ret = 0;
359
360
147k
    PARSE_2_DIGITS(dt->mon, cur, VALID_MONTH, ret);
361
147k
    if (ret != 0)
362
12.3k
  return ret;
363
364
135k
    *str = cur;
365
366
#ifdef DEBUG_EXSLT_DATE
367
    xsltGenericDebug(xsltGenericDebugContext,
368
         "Parsed month %02i\n", dt->mon);
369
#endif
370
371
135k
    return 0;
372
147k
}
373
374
/**
375
 * _exsltDateParseGDay:
376
 * @dt:  pointer to a date structure
377
 * @str: pointer to the string to analyze
378
 *
379
 * Parses a xs:gDay without time zone and fills in the appropriate
380
 * field of the @dt structure. @str is updated to point just after the
381
 * xs:gDay.
382
 *
383
 * Returns 0 or the error code
384
 */
385
static int
386
_exsltDateParseGDay (exsltDateValPtr dt, const xmlChar **str)
387
125k
{
388
125k
    const xmlChar *cur = *str;
389
125k
    int ret = 0;
390
391
125k
    PARSE_2_DIGITS(dt->day, cur, VALID_DAY, ret);
392
125k
    if (ret != 0)
393
12.5k
  return ret;
394
395
112k
    *str = cur;
396
397
#ifdef DEBUG_EXSLT_DATE
398
    xsltGenericDebug(xsltGenericDebugContext,
399
         "Parsed day %02i\n", dt->day);
400
#endif
401
402
112k
    return 0;
403
125k
}
404
405
/**
406
 * exsltFormatYearMonthDay:
407
 * @cur: a pointer to a pointer to an allocated buffer
408
 * @end: a pointer to the end of @cur buffer
409
 * @dt:  the #exsltDateVal to format
410
 *
411
 * Formats @dt in xsl:date format. Result is appended to @cur and
412
 * @cur is updated to point after the xsl:date.
413
 */
414
static void
415
exsltFormatYearMonthDay(xmlChar **cur, xmlChar *end, const exsltDateValPtr dt)
416
8.32k
{
417
8.32k
    exsltFormatGYear(cur, end, dt->year);
418
8.32k
    if (*cur < end)
419
8.32k
        *(*cur)++ = '-';
420
8.32k
    exsltFormat2Digits(cur, end, dt->mon);
421
8.32k
    if (*cur < end)
422
8.32k
        *(*cur)++ = '-';
423
8.32k
    exsltFormat2Digits(cur, end, dt->day);
424
8.32k
}
425
426
/**
427
 * _exsltDateParseTime:
428
 * @dt:  pointer to a date structure
429
 * @str: pointer to the string to analyze
430
 *
431
 * Parses a xs:time without time zone and fills in the appropriate
432
 * fields of the @dt structure. @str is updated to point just after the
433
 * xs:time.
434
 * In case of error, values of @dt fields are undefined.
435
 *
436
 * Returns 0 or the error code
437
 */
438
static int
439
_exsltDateParseTime (exsltDateValPtr dt, const xmlChar **str)
440
192k
{
441
192k
    const xmlChar *cur = *str;
442
192k
    unsigned int hour = 0; /* use temp var in case str is not xs:time */
443
192k
    int ret = 0;
444
445
192k
    PARSE_2_DIGITS(hour, cur, VALID_HOUR, ret);
446
192k
    if (ret != 0)
447
24.0k
  return ret;
448
449
168k
    if (*cur != ':')
450
87.5k
  return 1;
451
80.5k
    cur++;
452
453
    /* the ':' insures this string is xs:time */
454
80.5k
    dt->hour = hour;
455
456
80.5k
    PARSE_2_DIGITS(dt->min, cur, VALID_MIN, ret);
457
80.5k
    if (ret != 0)
458
4.49k
  return ret;
459
460
76.0k
    if (*cur != ':')
461
1.27k
  return 1;
462
74.8k
    cur++;
463
464
74.8k
    PARSE_FLOAT(dt->sec, cur, ret);
465
74.8k
    if (ret != 0)
466
3.94k
  return ret;
467
468
70.8k
    if (!VALID_TIME(dt))
469
805
  return 2;
470
471
70.0k
    *str = cur;
472
473
#ifdef DEBUG_EXSLT_DATE
474
    xsltGenericDebug(xsltGenericDebugContext,
475
         "Parsed time %02i:%02i:%02.f\n",
476
         dt->hour, dt->min, dt->sec);
477
#endif
478
479
70.0k
    return 0;
480
70.8k
}
481
482
/**
483
 * _exsltDateParseTimeZone:
484
 * @dt:  pointer to a date structure
485
 * @str: pointer to the string to analyze
486
 *
487
 * Parses a time zone without time zone and fills in the appropriate
488
 * field of the @dt structure. @str is updated to point just after the
489
 * time zone.
490
 *
491
 * Returns 0 or the error code
492
 */
493
static int
494
_exsltDateParseTimeZone (exsltDateValPtr dt, const xmlChar **str)
495
380k
{
496
380k
    const xmlChar *cur;
497
380k
    int ret = 0;
498
499
380k
    if (str == NULL)
500
0
  return -1;
501
380k
    cur = *str;
502
380k
    switch (*cur) {
503
66.0k
    case 0:
504
66.0k
  dt->tz_flag = 0;
505
66.0k
  dt->tzo = 0;
506
66.0k
  break;
507
508
34.2k
    case 'Z':
509
34.2k
  dt->tz_flag = 1;
510
34.2k
  dt->tzo = 0;
511
34.2k
  cur++;
512
34.2k
  break;
513
514
7.02k
    case '+':
515
277k
    case '-': {
516
277k
  int isneg = 0, tmp = 0;
517
277k
  isneg = (*cur == '-');
518
519
277k
  cur++;
520
521
277k
  PARSE_2_DIGITS(tmp, cur, VALID_HOUR, ret);
522
277k
  if (ret != 0)
523
102k
      return ret;
524
525
175k
  if (*cur != ':')
526
149k
      return 1;
527
25.5k
  cur++;
528
529
25.5k
  dt->tzo = tmp * 60;
530
531
25.5k
  PARSE_2_DIGITS(tmp, cur, VALID_MIN, ret);
532
25.5k
  if (ret != 0)
533
3.63k
      return ret;
534
535
21.9k
  dt->tzo += tmp;
536
21.9k
  if (isneg)
537
19.3k
      dt->tzo = - dt->tzo;
538
539
21.9k
  if (!VALID_TZO(dt->tzo))
540
0
      return 2;
541
542
21.9k
  break;
543
21.9k
      }
544
21.9k
    default:
545
2.04k
  return 1;
546
380k
    }
547
548
122k
    *str = cur;
549
550
#ifdef DEBUG_EXSLT_DATE
551
    xsltGenericDebug(xsltGenericDebugContext,
552
         "Parsed time zone offset (%s) %i\n",
553
         dt->tz_flag ? "explicit" : "implicit", dt->tzo);
554
#endif
555
556
122k
    return 0;
557
380k
}
558
559
/**
560
 * exsltFormatTimeZone:
561
 * @cur: a pointer to a pointer to an allocated buffer
562
 * @end: a pointer to the end of @cur buffer
563
 * @tzo: the timezone offset to format
564
 *
565
 * Formats @tzo timezone. Result is appended to @cur and
566
 * @cur is updated to point after the timezone.
567
 */
568
static void
569
exsltFormatTimeZone(xmlChar **cur, xmlChar *end, int tzo)
570
7.47k
{
571
7.47k
    if (tzo == 0) {
572
4.34k
        if (*cur < end)
573
4.34k
            *(*cur)++ = 'Z';
574
4.34k
    } else {
575
3.12k
        unsigned int aTzo = (tzo < 0) ? -tzo : tzo;
576
3.12k
        unsigned int tzHh = aTzo / 60, tzMm = aTzo % 60;
577
3.12k
        if (*cur < end)
578
3.12k
            *(*cur)++ = (tzo < 0) ? '-' : '+';
579
3.12k
        exsltFormat2Digits(cur, end, tzHh);
580
3.12k
        if (*cur < end)
581
3.12k
            *(*cur)++ = ':';
582
3.12k
        exsltFormat2Digits(cur, end, tzMm);
583
3.12k
    }
584
7.47k
}
585
586
/****************************************************************
587
 *                *
588
 *  XML Schema Dates/Times Datatypes Handling   *
589
 *                *
590
 ****************************************************************/
591
592
/**
593
 * exsltDateCreateDate:
594
 * @type:       type to create
595
 *
596
 * Creates a new #exsltDateVal, uninitialized.
597
 *
598
 * Returns the #exsltDateValPtr
599
 */
600
static exsltDateValPtr
601
exsltDateCreateDate (exsltDateType type)
602
221k
{
603
221k
    exsltDateValPtr ret;
604
605
221k
    ret = (exsltDateValPtr) xmlMalloc(sizeof(exsltDateVal));
606
221k
    if (ret == NULL) {
607
44
  xsltGenericError(xsltGenericErrorContext,
608
44
       "exsltDateCreateDate: out of memory\n");
609
44
  return (NULL);
610
44
    }
611
221k
    memset (ret, 0, sizeof(exsltDateVal));
612
613
221k
    ret->mon = 1;
614
221k
    ret->day = 1;
615
616
221k
    if (type != EXSLT_UNKNOWN)
617
13.9k
        ret->type = type;
618
619
221k
    return ret;
620
221k
}
621
622
/**
623
 * exsltDateFreeDate:
624
 * @date: an #exsltDateValPtr
625
 *
626
 * Frees up the @date
627
 */
628
static void
629
221k
exsltDateFreeDate (exsltDateValPtr date) {
630
221k
    if (date == NULL)
631
0
  return;
632
633
221k
    xmlFree(date);
634
221k
}
635
636
/**
637
 * exsltDateCreateDuration:
638
 *
639
 * Creates a new #exsltDateDurVal, uninitialized.
640
 *
641
 * Returns the #exsltDateDurValPtr
642
 */
643
static exsltDateDurValPtr
644
exsltDateCreateDuration (void)
645
38.0k
{
646
38.0k
    exsltDateDurValPtr ret;
647
648
38.0k
    ret = (exsltDateDurValPtr) xmlMalloc(sizeof(exsltDateDurVal));
649
38.0k
    if (ret == NULL) {
650
13
  xsltGenericError(xsltGenericErrorContext,
651
13
       "exsltDateCreateDuration: out of memory\n");
652
13
  return (NULL);
653
13
    }
654
38.0k
    memset (ret, 0, sizeof(exsltDateDurVal));
655
656
38.0k
    return ret;
657
38.0k
}
658
659
/**
660
 * exsltDateFreeDuration:
661
 * @date: an #exsltDateDurValPtr
662
 *
663
 * Frees up the @duration
664
 */
665
static void
666
38.0k
exsltDateFreeDuration (exsltDateDurValPtr duration) {
667
38.0k
    if (duration == NULL)
668
0
  return;
669
670
38.0k
    xmlFree(duration);
671
38.0k
}
672
673
/**
674
 * exsltDateCurrent:
675
 *
676
 * Returns the current date and time.
677
 */
678
static exsltDateValPtr
679
exsltDateCurrent (void)
680
3.49k
{
681
3.49k
    struct tm localTm, gmTm;
682
#if !defined(HAVE_GMTIME_R) && !defined(HAVE_MSVCRT)
683
    struct tm *tb = NULL;
684
#endif
685
3.49k
    time_t secs;
686
3.49k
    int local_s, gm_s;
687
3.49k
    exsltDateValPtr ret;
688
3.49k
    char *source_date_epoch;
689
3.49k
    int override = 0;
690
691
3.49k
    ret = exsltDateCreateDate(XS_DATETIME);
692
3.49k
    if (ret == NULL)
693
16
        return NULL;
694
695
    /*
696
     * Allow the date and time to be set externally by an exported
697
     * environment variable to enable reproducible builds.
698
     */
699
3.47k
    source_date_epoch = getenv("SOURCE_DATE_EPOCH");
700
3.47k
    if (source_date_epoch) {
701
0
        errno = 0;
702
0
  secs = (time_t) strtol (source_date_epoch, NULL, 10);
703
0
  if (errno == 0) {
704
#ifdef HAVE_MSVCRT
705
      struct tm *gm = gmtime_s(&localTm, &secs) ? NULL : &localTm;
706
      if (gm != NULL)
707
          override = 1;
708
#elif HAVE_GMTIME_R
709
0
      if (gmtime_r(&secs, &localTm) != NULL)
710
0
          override = 1;
711
#else
712
      tb = gmtime(&secs);
713
      if (tb != NULL) {
714
          localTm = *tb;
715
    override = 1;
716
      }
717
#endif
718
0
        }
719
0
    }
720
721
3.47k
    if (override == 0) {
722
    /* get current time */
723
3.47k
  secs    = time(NULL);
724
725
#ifdef HAVE_MSVCRT
726
  localtime_s(&localTm, &secs);
727
#elif HAVE_LOCALTIME_R
728
  localtime_r(&secs, &localTm);
729
#else
730
  localTm = *localtime(&secs);
731
#endif
732
3.47k
    }
733
734
    /* get real year, not years since 1900 */
735
3.47k
    ret->year = localTm.tm_year + 1900;
736
737
3.47k
    ret->mon  = localTm.tm_mon + 1;
738
3.47k
    ret->day  = localTm.tm_mday;
739
3.47k
    ret->hour = localTm.tm_hour;
740
3.47k
    ret->min  = localTm.tm_min;
741
742
    /* floating point seconds */
743
3.47k
    ret->sec  = (double) localTm.tm_sec;
744
745
    /* determine the time zone offset from local to gm time */
746
#ifdef HAVE_MSVCRT
747
    gmtime_s(&gmTm, &secs);
748
#elif HAVE_GMTIME_R
749
    gmtime_r(&secs, &gmTm);
750
#else
751
    tb = gmtime(&secs);
752
    if (tb == NULL)
753
        return NULL;
754
    gmTm = *tb;
755
#endif
756
3.47k
    ret->tz_flag = 0;
757
#if 0
758
    ret->tzo = (((ret->day * 1440) +
759
                 (ret->hour * 60) +
760
                  ret->min) -
761
                ((gmTm.tm_mday * 1440) + (gmTm.tm_hour * 60) +
762
                  gmTm.tm_min));
763
#endif
764
3.47k
    local_s = localTm.tm_hour * SECS_PER_HOUR +
765
3.47k
        localTm.tm_min * SECS_PER_MIN +
766
3.47k
        localTm.tm_sec;
767
768
3.47k
    gm_s = gmTm.tm_hour * SECS_PER_HOUR +
769
3.47k
        gmTm.tm_min * SECS_PER_MIN +
770
3.47k
        gmTm.tm_sec;
771
772
3.47k
    if (localTm.tm_year < gmTm.tm_year) {
773
0
  ret->tzo = -((SECS_PER_DAY - local_s) + gm_s)/60;
774
3.47k
    } else if (localTm.tm_year > gmTm.tm_year) {
775
0
  ret->tzo = ((SECS_PER_DAY - gm_s) + local_s)/60;
776
3.47k
    } else if (localTm.tm_mon < gmTm.tm_mon) {
777
0
  ret->tzo = -((SECS_PER_DAY - local_s) + gm_s)/60;
778
3.47k
    } else if (localTm.tm_mon > gmTm.tm_mon) {
779
0
  ret->tzo = ((SECS_PER_DAY - gm_s) + local_s)/60;
780
3.47k
    } else if (localTm.tm_mday < gmTm.tm_mday) {
781
0
  ret->tzo = -((SECS_PER_DAY - local_s) + gm_s)/60;
782
3.47k
    } else if (localTm.tm_mday > gmTm.tm_mday) {
783
0
  ret->tzo = ((SECS_PER_DAY - gm_s) + local_s)/60;
784
3.47k
    } else  {
785
3.47k
  ret->tzo = (local_s - gm_s)/60;
786
3.47k
    }
787
788
3.47k
    return ret;
789
3.49k
}
790
791
/**
792
 * exsltDateParse:
793
 * @dateTime:  string to analyze
794
 *
795
 * Parses a date/time string
796
 *
797
 * Returns a newly built #exsltDateValPtr of NULL in case of error
798
 */
799
static exsltDateValPtr
800
exsltDateParse (const xmlChar *dateTime)
801
207k
{
802
207k
    exsltDateValPtr dt;
803
207k
    int ret;
804
207k
    const xmlChar *cur = dateTime;
805
806
207k
#define RETURN_TYPE_IF_VALID(t)         \
807
393k
    if (IS_TZO_CHAR(*cur)) {         \
808
321k
  ret = _exsltDateParseTimeZone(dt, &cur);    \
809
321k
  if (ret == 0) {           \
810
67.0k
      if (*cur != 0)         \
811
67.0k
    goto error;         \
812
67.0k
      dt->type = t;         \
813
64.5k
      return dt;           \
814
67.0k
  }              \
815
321k
    }
816
817
207k
    if (dateTime == NULL)
818
0
  return NULL;
819
820
207k
    if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
821
0
  return NULL;
822
823
207k
    dt = exsltDateCreateDate(EXSLT_UNKNOWN);
824
207k
    if (dt == NULL)
825
25
  return NULL;
826
827
207k
    if ((cur[0] == '-') && (cur[1] == '-')) {
828
  /*
829
   * It's an incomplete date (xs:gMonthDay, xs:gMonth or
830
   * xs:gDay)
831
   */
832
18.0k
  cur += 2;
833
834
  /* is it an xs:gDay? */
835
18.0k
  if (*cur == '-') {
836
4.20k
    ++cur;
837
4.20k
      ret = _exsltDateParseGDay(dt, &cur);
838
4.20k
      if (ret != 0)
839
1.93k
    goto error;
840
841
2.26k
      RETURN_TYPE_IF_VALID(XS_GDAY);
842
843
509
      goto error;
844
2.26k
  }
845
846
  /*
847
   * it should be an xs:gMonthDay or xs:gMonth
848
   */
849
13.8k
  ret = _exsltDateParseGMonth(dt, &cur);
850
13.8k
  if (ret != 0)
851
3.24k
      goto error;
852
853
10.6k
  if (*cur != '-')
854
163
      goto error;
855
10.4k
  cur++;
856
857
  /* is it an xs:gMonth? */
858
10.4k
  if (*cur == '-') {
859
4.15k
      cur++;
860
4.15k
      RETURN_TYPE_IF_VALID(XS_GMONTH);
861
286
      goto error;
862
4.15k
  }
863
864
  /* it should be an xs:gMonthDay */
865
6.29k
  ret = _exsltDateParseGDay(dt, &cur);
866
6.29k
  if (ret != 0)
867
3.31k
      goto error;
868
869
2.98k
  RETURN_TYPE_IF_VALID(XS_GMONTHDAY);
870
871
961
  goto error;
872
2.98k
    }
873
874
    /*
875
     * It's a right-truncated date or an xs:time.
876
     * Try to parse an xs:time then fallback on right-truncated dates.
877
     */
878
189k
    if ((*cur >= '0') && (*cur <= '9')) {
879
125k
  ret = _exsltDateParseTime(dt, &cur);
880
125k
  if (ret == 0) {
881
      /* it's an xs:time */
882
10.7k
      RETURN_TYPE_IF_VALID(XS_TIME);
883
2.26k
  }
884
125k
    }
885
886
    /* fallback on date parsing */
887
181k
    cur = dateTime;
888
889
181k
    ret = _exsltDateParseGYear(dt, &cur);
890
181k
    if (ret != 0)
891
38.2k
  goto error;
892
893
    /* is it an xs:gYear? */
894
143k
    RETURN_TYPE_IF_VALID(XS_GYEAR);
895
896
135k
    if (*cur != '-')
897
1.83k
  goto error;
898
133k
    cur++;
899
900
133k
    ret = _exsltDateParseGMonth(dt, &cur);
901
133k
    if (ret != 0)
902
9.06k
  goto error;
903
904
    /* is it an xs:gYearMonth? */
905
124k
    RETURN_TYPE_IF_VALID(XS_GYEARMONTH);
906
907
118k
    if (*cur != '-')
908
3.81k
  goto error;
909
114k
    cur++;
910
911
114k
    ret = _exsltDateParseGDay(dt, &cur);
912
114k
    if ((ret != 0) || !VALID_DATE(dt))
913
8.31k
  goto error;
914
915
    /* is it an xs:date? */
916
106k
    RETURN_TYPE_IF_VALID(XS_DATE);
917
918
69.1k
    if (*cur != 'T')
919
2.61k
  goto error;
920
66.4k
    cur++;
921
922
    /* it should be an xs:dateTime */
923
66.4k
    ret = _exsltDateParseTime(dt, &cur);
924
66.4k
    if (ret != 0)
925
7.21k
  goto error;
926
927
59.2k
    ret = _exsltDateParseTimeZone(dt, &cur);
928
59.2k
    if ((ret != 0) || (*cur != 0) || !VALID_DATETIME(dt))
929
5.04k
  goto error;
930
931
54.2k
    dt->type = XS_DATETIME;
932
933
54.2k
    return dt;
934
935
88.9k
error:
936
88.9k
    if (dt != NULL)
937
88.9k
  exsltDateFreeDate(dt);
938
88.9k
    return NULL;
939
59.2k
}
940
941
/**
942
 * exsltDateParseDuration:
943
 * @duration:  string to analyze
944
 *
945
 * Parses a duration string
946
 *
947
 * Returns a newly built #exsltDateDurValPtr of NULL in case of error
948
 */
949
static exsltDateDurValPtr
950
exsltDateParseDuration (const xmlChar *duration)
951
33.2k
{
952
33.2k
    const xmlChar  *cur = duration;
953
33.2k
    exsltDateDurValPtr dur;
954
33.2k
    int isneg = 0;
955
33.2k
    unsigned int seq = 0;
956
33.2k
    long days, secs = 0;
957
33.2k
    double sec_frac = 0.0;
958
959
33.2k
    if (duration == NULL)
960
0
  return NULL;
961
962
33.2k
    if (*cur == '-') {
963
9.87k
        isneg = 1;
964
9.87k
        cur++;
965
9.87k
    }
966
967
    /* duration must start with 'P' (after sign) */
968
33.2k
    if (*cur++ != 'P')
969
6.71k
  return NULL;
970
971
26.4k
    if (*cur == 0)
972
106
  return NULL;
973
974
26.3k
    dur = exsltDateCreateDuration();
975
26.3k
    if (dur == NULL)
976
3
  return NULL;
977
978
60.0k
    while (*cur != 0) {
979
36.9k
        long           num = 0;
980
36.9k
        size_t         has_digits = 0;
981
36.9k
        int            has_frac = 0;
982
36.9k
        const xmlChar  desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
983
984
        /* input string should be empty or invalid date/time item */
985
36.9k
        if (seq >= sizeof(desig))
986
301
            goto error;
987
988
        /* T designator must be present for time items */
989
36.6k
        if (*cur == 'T') {
990
12.5k
            if (seq > 3)
991
160
                goto error;
992
12.3k
            cur++;
993
12.3k
            seq = 3;
994
24.1k
        } else if (seq == 3)
995
125
            goto error;
996
997
        /* Parse integral part. */
998
165k
        while (*cur >= '0' && *cur <= '9') {
999
129k
            long digit = *cur - '0';
1000
1001
129k
            if (num > LONG_MAX / 10)
1002
241
                goto error;
1003
129k
            num *= 10;
1004
129k
            if (num > LONG_MAX - digit)
1005
13
                goto error;
1006
128k
            num += digit;
1007
1008
128k
            has_digits = 1;
1009
128k
            cur++;
1010
128k
        }
1011
1012
36.1k
        if (*cur == '.') {
1013
            /* Parse fractional part. */
1014
1.86k
            double mult = 1.0;
1015
1.86k
            cur++;
1016
1.86k
            has_frac = 1;
1017
5.42k
            while (*cur >= '0' && *cur <= '9') {
1018
3.55k
                mult /= 10.0;
1019
3.55k
                sec_frac += (*cur - '0') * mult;
1020
3.55k
                has_digits = 1;
1021
3.55k
                cur++;
1022
3.55k
            }
1023
1.86k
        }
1024
1025
69.0k
        while (*cur != desig[seq]) {
1026
34.6k
            seq++;
1027
            /* No T designator or invalid char. */
1028
34.6k
            if (seq == 3 || seq == sizeof(desig))
1029
1.72k
                goto error;
1030
34.6k
        }
1031
34.4k
        cur++;
1032
1033
34.4k
        if (!has_digits || (has_frac && (seq != 5)))
1034
514
            goto error;
1035
1036
33.8k
        switch (seq) {
1037
3.39k
            case 0:
1038
                /* Year */
1039
3.39k
                if (num > LONG_MAX / 12)
1040
86
                    goto error;
1041
3.31k
                dur->mon = num * 12;
1042
3.31k
                break;
1043
9.56k
            case 1:
1044
                /* Month */
1045
9.56k
                if (dur->mon > LONG_MAX - num)
1046
3
                    goto error;
1047
9.56k
                dur->mon += num;
1048
9.56k
                break;
1049
6.17k
            case 2:
1050
                /* Day */
1051
6.17k
                dur->day = num;
1052
6.17k
                break;
1053
2.09k
            case 3:
1054
                /* Hour */
1055
2.09k
                days = num / HOURS_PER_DAY;
1056
2.09k
                if (dur->day > LONG_MAX - days)
1057
76
                    goto error;
1058
2.02k
                dur->day += days;
1059
2.02k
                secs = (num % HOURS_PER_DAY) * SECS_PER_HOUR;
1060
2.02k
                break;
1061
4.53k
            case 4:
1062
                /* Minute */
1063
4.53k
                days = num / MINS_PER_DAY;
1064
4.53k
                if (dur->day > LONG_MAX - days)
1065
3
                    goto error;
1066
4.53k
                dur->day += days;
1067
4.53k
                secs += (num % MINS_PER_DAY) * SECS_PER_MIN;
1068
4.53k
                break;
1069
8.12k
            case 5:
1070
                /* Second */
1071
8.12k
                days = num / SECS_PER_DAY;
1072
8.12k
                if (dur->day > LONG_MAX - days)
1073
12
                    goto error;
1074
8.10k
                dur->day += days;
1075
8.10k
                secs += num % SECS_PER_DAY;
1076
8.10k
                break;
1077
33.8k
        }
1078
1079
33.7k
        seq++;
1080
33.7k
    }
1081
1082
23.1k
    days = secs / SECS_PER_DAY;
1083
23.1k
    if (dur->day > LONG_MAX - days)
1084
0
        goto error;
1085
23.1k
    dur->day += days;
1086
23.1k
    dur->sec = (secs % SECS_PER_DAY) + sec_frac;
1087
1088
23.1k
    if (isneg) {
1089
9.03k
        dur->mon = -dur->mon;
1090
9.03k
        dur->day = -dur->day;
1091
9.03k
        if (dur->sec != 0.0) {
1092
3.85k
            dur->sec = SECS_PER_DAY - dur->sec;
1093
3.85k
            dur->day -= 1;
1094
3.85k
        }
1095
9.03k
    }
1096
1097
#ifdef DEBUG_EXSLT_DATE
1098
    xsltGenericDebug(xsltGenericDebugContext,
1099
         "Parsed duration %f\n", dur->sec);
1100
#endif
1101
1102
23.1k
    return dur;
1103
1104
3.25k
error:
1105
3.25k
    if (dur != NULL)
1106
3.25k
  exsltDateFreeDuration(dur);
1107
3.25k
    return NULL;
1108
23.1k
}
1109
1110
static void
1111
14.7k
exsltFormatLong(xmlChar **cur, xmlChar *end, long num) {
1112
14.7k
    xmlChar buf[20];
1113
14.7k
    int i = 0;
1114
1115
39.3k
    while (i < 20) {
1116
39.3k
        buf[i++] = '0' + num % 10;
1117
39.3k
        num /= 10;
1118
39.3k
        if (num == 0)
1119
14.7k
            break;
1120
39.3k
    }
1121
1122
54.0k
    while (i > 0) {
1123
39.3k
        if (*cur < end)
1124
39.3k
            *(*cur)++ = buf[--i];
1125
39.3k
    }
1126
14.7k
}
1127
1128
static void
1129
10.0k
exsltFormatNanoseconds(xmlChar **cur, xmlChar *end, long nsecs) {
1130
10.0k
    long p10, digit;
1131
1132
10.0k
    if (nsecs > 0) {
1133
2.04k
        if (*cur < end)
1134
2.04k
            *(*cur)++ = '.';
1135
2.04k
        p10 = 100000000;
1136
9.17k
        while (nsecs > 0) {
1137
7.13k
            digit = nsecs / p10;
1138
7.13k
            if (*cur < end)
1139
7.13k
                *(*cur)++ = '0' + digit;
1140
7.13k
            nsecs -= digit * p10;
1141
7.13k
            p10 /= 10;
1142
7.13k
        }
1143
2.04k
    }
1144
10.0k
}
1145
1146
/**
1147
 * exsltDateFormatDuration:
1148
 * @dur: an #exsltDateDurValPtr
1149
 *
1150
 * Formats the duration.
1151
 *
1152
 * Returns a newly allocated string, or NULL in case of error
1153
 */
1154
static xmlChar *
1155
exsltDateFormatDuration (const exsltDateDurValPtr dur)
1156
7.38k
{
1157
7.38k
    xmlChar buf[100], *cur = buf, *end = buf + 99;
1158
7.38k
    double secs, tmp;
1159
7.38k
    long days, months, intSecs, nsecs;
1160
1161
7.38k
    if (dur == NULL)
1162
0
  return NULL;
1163
1164
    /* quick and dirty check */
1165
7.38k
    if ((dur->sec == 0.0) && (dur->day == 0) && (dur->mon == 0))
1166
728
        return xmlStrdup((xmlChar*)"P0D");
1167
1168
6.65k
    secs   = dur->sec;
1169
6.65k
    days   = dur->day;
1170
6.65k
    months = dur->mon;
1171
1172
6.65k
    *cur = '\0';
1173
6.65k
    if (days < 0) {
1174
1.30k
        if (secs != 0.0) {
1175
1.13k
            secs = SECS_PER_DAY - secs;
1176
1.13k
            days += 1;
1177
1.13k
        }
1178
1.30k
        days = -days;
1179
1.30k
        *cur = '-';
1180
1.30k
    }
1181
6.65k
    if (months < 0) {
1182
900
        months = -months;
1183
900
        *cur = '-';
1184
900
    }
1185
6.65k
    if (*cur == '-')
1186
2.02k
  cur++;
1187
1188
6.65k
    *cur++ = 'P';
1189
1190
6.65k
    if (months >= 12) {
1191
2.53k
        long years = months / 12;
1192
1193
2.53k
        months -= years * 12;
1194
2.53k
        exsltFormatLong(&cur, end, years);
1195
2.53k
        if (cur < end)
1196
2.53k
            *cur++ = 'Y';
1197
2.53k
    }
1198
1199
6.65k
    if (months != 0) {
1200
1.61k
        exsltFormatLong(&cur, end, months);
1201
1.61k
        if (cur < end)
1202
1.61k
            *cur++ = 'M';
1203
1.61k
    }
1204
1205
6.65k
    if (days != 0) {
1206
2.69k
        exsltFormatLong(&cur, end, days);
1207
2.69k
        if (cur < end)
1208
2.69k
            *cur++ = 'D';
1209
2.69k
    }
1210
1211
6.65k
    tmp = floor(secs);
1212
6.65k
    intSecs = (long) tmp;
1213
    /* Round to nearest to avoid issues with floating point precision */
1214
6.65k
    nsecs = (long) floor((secs - tmp) * 1000000000 + 0.5);
1215
6.65k
    if (nsecs >= 1000000000) {
1216
572
        nsecs -= 1000000000;
1217
572
        intSecs += 1;
1218
572
    }
1219
1220
6.65k
    if ((intSecs > 0) || (nsecs > 0)) {
1221
3.85k
        if (cur < end)
1222
3.85k
            *cur++ = 'T';
1223
1224
3.85k
        if (intSecs >= SECS_PER_HOUR) {
1225
2.60k
            long hours = intSecs / SECS_PER_HOUR;
1226
1227
2.60k
            intSecs -= hours * SECS_PER_HOUR;
1228
2.60k
            exsltFormatLong(&cur, end, hours);
1229
2.60k
            if (cur < end)
1230
2.60k
                *cur++ = 'H';
1231
2.60k
        }
1232
1233
3.85k
        if (intSecs >= SECS_PER_MIN) {
1234
2.59k
            long mins = intSecs / SECS_PER_MIN;
1235
1236
2.59k
            intSecs -= mins * SECS_PER_MIN;
1237
2.59k
            exsltFormatLong(&cur, end, mins);
1238
2.59k
            if (cur < end)
1239
2.59k
                *cur++ = 'M';
1240
2.59k
        }
1241
1242
3.85k
        if ((intSecs > 0) || (nsecs > 0)) {
1243
2.68k
            exsltFormatLong(&cur, end, intSecs);
1244
2.68k
            exsltFormatNanoseconds(&cur, end, nsecs);
1245
2.68k
            if (cur < end)
1246
2.68k
                *cur++ = 'S';
1247
2.68k
        }
1248
3.85k
    }
1249
1250
6.65k
    *cur = 0;
1251
1252
6.65k
    return xmlStrdup(buf);
1253
7.38k
}
1254
1255
static void
1256
22.1k
exsltFormatTwoDigits(xmlChar **cur, xmlChar *end, int num) {
1257
22.1k
    if (num < 0 || num >= 100)
1258
0
        return;
1259
22.1k
    if (*cur < end)
1260
22.1k
        *(*cur)++ = '0' + num / 10;
1261
22.1k
    if (*cur < end)
1262
22.1k
        *(*cur)++ = '0' + num % 10;
1263
22.1k
}
1264
1265
static void
1266
7.37k
exsltFormatTime(xmlChar **cur, xmlChar *end, exsltDateValPtr dt) {
1267
7.37k
    double tmp;
1268
7.37k
    long intSecs, nsecs;
1269
1270
7.37k
    exsltFormatTwoDigits(cur, end, dt->hour);
1271
7.37k
    if (*cur < end)
1272
7.37k
        *(*cur)++ = ':';
1273
1274
7.37k
    exsltFormatTwoDigits(cur, end, dt->min);
1275
7.37k
    if (*cur < end)
1276
7.37k
        *(*cur)++ = ':';
1277
1278
7.37k
    tmp = floor(dt->sec);
1279
7.37k
    intSecs = (long) tmp;
1280
    /*
1281
     * Round to nearest to avoid issues with floating point precision,
1282
     * but don't carry over so seconds stay below 60.
1283
     */
1284
7.37k
    nsecs = (long) floor((dt->sec - tmp) * 1000000000 + 0.5);
1285
7.37k
    if (nsecs > 999999999)
1286
29
        nsecs = 999999999;
1287
7.37k
    exsltFormatTwoDigits(cur, end, intSecs);
1288
7.37k
    exsltFormatNanoseconds(cur, end, nsecs);
1289
7.37k
}
1290
1291
/**
1292
 * exsltDateFormatDateTime:
1293
 * @dt: an #exsltDateValPtr
1294
 *
1295
 * Formats @dt in xs:dateTime format.
1296
 *
1297
 * Returns a newly allocated string, or NULL in case of error
1298
 */
1299
static xmlChar *
1300
exsltDateFormatDateTime (const exsltDateValPtr dt)
1301
3.73k
{
1302
3.73k
    xmlChar buf[100], *cur = buf, *end = buf + 99;
1303
1304
3.73k
    if ((dt == NULL) || !VALID_DATETIME(dt))
1305
0
  return NULL;
1306
1307
3.73k
    exsltFormatYearMonthDay(&cur, end, dt);
1308
3.73k
    if (cur < end)
1309
3.73k
        *cur++ = 'T';
1310
3.73k
    exsltFormatTime(&cur, end, dt);
1311
3.73k
    exsltFormatTimeZone(&cur, end, dt->tzo);
1312
3.73k
    *cur = 0;
1313
1314
3.73k
    return xmlStrdup(buf);
1315
3.73k
}
1316
1317
/**
1318
 * exsltDateFormatDate:
1319
 * @dt: an #exsltDateValPtr
1320
 *
1321
 * Formats @dt in xs:date format.
1322
 *
1323
 * Returns a newly allocated string, or NULL in case of error
1324
 */
1325
static xmlChar *
1326
exsltDateFormatDate (const exsltDateValPtr dt)
1327
4.59k
{
1328
4.59k
    xmlChar buf[100], *cur = buf, *end = buf + 99;
1329
1330
4.59k
    if ((dt == NULL) || !VALID_DATETIME(dt))
1331
0
  return NULL;
1332
1333
4.59k
    exsltFormatYearMonthDay(&cur, end, dt);
1334
4.59k
    if (dt->tz_flag || (dt->tzo != 0)) {
1335
1.40k
        exsltFormatTimeZone(&cur, end, dt->tzo);
1336
1.40k
    }
1337
4.59k
    *cur = 0;
1338
1339
4.59k
    return xmlStrdup(buf);
1340
4.59k
}
1341
1342
/**
1343
 * exsltDateFormatTime:
1344
 * @dt: an #exsltDateValPtr
1345
 *
1346
 * Formats @dt in xs:time format.
1347
 *
1348
 * Returns a newly allocated string, or NULL in case of error
1349
 */
1350
static xmlChar *
1351
exsltDateFormatTime (const exsltDateValPtr dt)
1352
3.63k
{
1353
3.63k
    xmlChar buf[100], *cur = buf, *end = buf + 99;
1354
1355
3.63k
    if ((dt == NULL) || !VALID_TIME(dt))
1356
0
  return NULL;
1357
1358
3.63k
    exsltFormatTime(&cur, end, dt);
1359
3.63k
    if (dt->tz_flag || (dt->tzo != 0)) {
1360
2.20k
        exsltFormatTimeZone(&cur, end, dt->tzo);
1361
2.20k
    }
1362
3.63k
    *cur = 0;
1363
1364
3.63k
    return xmlStrdup(buf);
1365
3.63k
}
1366
1367
/**
1368
 * exsltDateFormat:
1369
 * @dt: an #exsltDateValPtr
1370
 *
1371
 * Formats @dt in the proper format.
1372
 * Note: xs:gmonth and xs:gday are not formatted as there are no
1373
 * routines that output them.
1374
 *
1375
 * Returns a newly allocated string, or NULL in case of error
1376
 */
1377
static xmlChar *
1378
exsltDateFormat (const exsltDateValPtr dt)
1379
7.78k
{
1380
7.78k
    if (dt == NULL)
1381
0
  return NULL;
1382
1383
7.78k
    switch (dt->type) {
1384
3.73k
    case XS_DATETIME:
1385
3.73k
        return exsltDateFormatDateTime(dt);
1386
3.08k
    case XS_DATE:
1387
3.08k
        return exsltDateFormatDate(dt);
1388
0
    case XS_TIME:
1389
0
        return exsltDateFormatTime(dt);
1390
968
    default:
1391
968
        break;
1392
7.78k
    }
1393
1394
968
    if (dt->type & XS_GYEAR) {
1395
968
        xmlChar buf[100], *cur = buf, *end = buf + 99;
1396
1397
968
        exsltFormatGYear(&cur, end, dt->year);
1398
968
        if (dt->type == XS_GYEARMONTH) {
1399
542
            if (cur < end)
1400
542
          *cur++ = '-';
1401
542
            exsltFormat2Digits(&cur, end, dt->mon);
1402
542
        }
1403
1404
968
        if (dt->tz_flag || (dt->tzo != 0)) {
1405
120
            exsltFormatTimeZone(&cur, end, dt->tzo);
1406
120
        }
1407
968
        *cur = 0;
1408
968
        return xmlStrdup(buf);
1409
968
    }
1410
1411
0
    return NULL;
1412
968
}
1413
1414
/**
1415
 * _exsltDateCastYMToDays:
1416
 * @dt: an #exsltDateValPtr
1417
 *
1418
 * Convert mon and year of @dt to total number of days. Take the
1419
 * number of years since (or before) 1 AD and add the number of leap
1420
 * years. This is a function  because negative
1421
 * years must be handled a little differently.
1422
 *
1423
 * Returns number of days.
1424
 */
1425
static long
1426
_exsltDateCastYMToDays (const exsltDateValPtr dt)
1427
5.15k
{
1428
5.15k
    long ret;
1429
1430
5.15k
    if (dt->year <= 0)
1431
871
        ret = ((dt->year-1) * 365) +
1432
871
              (((dt->year)/4)-((dt->year)/100)+
1433
871
               ((dt->year)/400)) +
1434
871
              DAY_IN_YEAR(0, dt->mon, dt->year) - 1;
1435
4.28k
    else
1436
4.28k
        ret = ((dt->year-1) * 365) +
1437
4.28k
              (((dt->year-1)/4)-((dt->year-1)/100)+
1438
4.28k
               ((dt->year-1)/400)) +
1439
4.28k
              DAY_IN_YEAR(0, dt->mon, dt->year);
1440
1441
5.15k
    return ret;
1442
5.15k
}
1443
1444
/**
1445
 * TIME_TO_NUMBER:
1446
 * @dt:  an #exsltDateValPtr
1447
 *
1448
 * Calculates the number of seconds in the time portion of @dt.
1449
 *
1450
 * Returns seconds.
1451
 */
1452
#define TIME_TO_NUMBER(dt)                              \
1453
5.15k
    ((double)((dt->hour * SECS_PER_HOUR) +   \
1454
5.15k
              (dt->min * SECS_PER_MIN)) + dt->sec)
1455
1456
/**
1457
 * _exsltDateTruncateDate:
1458
 * @dt: an #exsltDateValPtr
1459
 * @type: dateTime type to set to
1460
 *
1461
 * Set @dt to truncated @type.
1462
 *
1463
 * Returns 0 success, non-zero otherwise.
1464
 */
1465
static int
1466
_exsltDateTruncateDate (exsltDateValPtr dt, exsltDateType type)
1467
2.28k
{
1468
2.28k
    if (dt == NULL)
1469
0
        return 1;
1470
1471
2.28k
    if ((type & XS_TIME) != XS_TIME) {
1472
2.28k
        dt->hour = 0;
1473
2.28k
        dt->min  = 0;
1474
2.28k
        dt->sec  = 0.0;
1475
2.28k
    }
1476
1477
2.28k
    if ((type & XS_GDAY) != XS_GDAY)
1478
761
        dt->day = 1;
1479
1480
2.28k
    if ((type & XS_GMONTH) != XS_GMONTH)
1481
650
        dt->mon = 1;
1482
1483
2.28k
    if ((type & XS_GYEAR) != XS_GYEAR)
1484
0
        dt->year = 0;
1485
1486
2.28k
    dt->type = type;
1487
1488
2.28k
    return 0;
1489
2.28k
}
1490
1491
/**
1492
 * _exsltDayInWeek:
1493
 * @yday: year day (1-366)
1494
 * @yr: year
1495
 *
1496
 * Determine the day-in-week from @yday and @yr. 0001-01-01 was
1497
 * a Monday so all other days are calculated from there. Take the
1498
 * number of years since (or before) add the number of leap years and
1499
 * the day-in-year and mod by 7. This is a function  because negative
1500
 * years must be handled a little differently.
1501
 *
1502
 * Returns day in week (Sunday = 0).
1503
 */
1504
static long
1505
_exsltDateDayInWeek(long yday, long yr)
1506
22.4k
{
1507
22.4k
    long ret;
1508
1509
22.4k
    if (yr <= 0) {
1510
        /* Compute modulus twice to avoid integer overflow */
1511
6.93k
        ret = ((yr%7-2 + ((yr/4)-(yr/100)+(yr/400)) + yday) % 7);
1512
6.93k
        if (ret < 0)
1513
3.88k
            ret += 7;
1514
6.93k
    } else
1515
15.4k
        ret = (((yr%7-1) + (((yr-1)/4)-((yr-1)/100)+((yr-1)/400)) + yday) % 7);
1516
1517
22.4k
    return ret;
1518
22.4k
}
1519
1520
/**
1521
 * _exsltDateAdd:
1522
 * @dt: an #exsltDateValPtr
1523
 * @dur: an #exsltDateDurValPtr
1524
 *
1525
 * Compute a new date/time from @dt and @dur. This function assumes @dt
1526
 * is either #XS_DATETIME, #XS_DATE, #XS_GYEARMONTH, or #XS_GYEAR.
1527
 *
1528
 * Returns date/time pointer or NULL.
1529
 */
1530
static exsltDateValPtr
1531
_exsltDateAdd (exsltDateValPtr dt, exsltDateDurValPtr dur)
1532
8.00k
{
1533
8.00k
    exsltDateValPtr ret;
1534
8.00k
    long carry, temp;
1535
8.00k
    double sum;
1536
1537
8.00k
    if ((dt == NULL) || (dur == NULL))
1538
0
        return NULL;
1539
1540
8.00k
    ret = exsltDateCreateDate(dt->type);
1541
8.00k
    if (ret == NULL)
1542
2
        return NULL;
1543
1544
    /*
1545
     * Note that temporary values may need more bits than the values in
1546
     * bit field.
1547
     */
1548
1549
    /* month */
1550
8.00k
    temp  = dt->mon + dur->mon % 12;
1551
8.00k
    carry = dur->mon / 12;
1552
8.00k
    if (temp < 1) {
1553
109
        temp  += 12;
1554
109
        carry -= 1;
1555
109
    }
1556
7.89k
    else if (temp > 12) {
1557
1
        temp  -= 12;
1558
1
        carry += 1;
1559
1
    }
1560
8.00k
    ret->mon = temp;
1561
1562
    /*
1563
     * year (may be modified later)
1564
     *
1565
     * Add epochs from dur->day now to avoid overflow later and to speed up
1566
     * pathological cases.
1567
     */
1568
8.00k
    carry += (dur->day / DAYS_PER_EPOCH) * YEARS_PER_EPOCH;
1569
8.00k
    if ((carry > 0 && dt->year > YEAR_MAX - carry) ||
1570
8.00k
        (carry < 0 && dt->year < YEAR_MIN - carry)) {
1571
        /* Overflow */
1572
192
        exsltDateFreeDate(ret);
1573
192
        return NULL;
1574
192
    }
1575
7.80k
    ret->year = dt->year + carry;
1576
1577
    /* time zone */
1578
7.80k
    ret->tzo     = dt->tzo;
1579
7.80k
    ret->tz_flag = dt->tz_flag;
1580
1581
    /* seconds */
1582
7.80k
    sum    = dt->sec + dur->sec;
1583
7.80k
    ret->sec = fmod(sum, 60.0);
1584
7.80k
    carry  = (long)(sum / 60.0);
1585
1586
    /* minute */
1587
7.80k
    temp  = dt->min + carry % 60;
1588
7.80k
    carry = carry / 60;
1589
7.80k
    if (temp >= 60) {
1590
428
        temp  -= 60;
1591
428
        carry += 1;
1592
428
    }
1593
7.80k
    ret->min = temp;
1594
1595
    /* hours */
1596
7.80k
    temp  = dt->hour + carry % 24;
1597
7.80k
    carry = carry / 24;
1598
7.80k
    if (temp >= 24) {
1599
437
        temp  -= 24;
1600
437
        carry += 1;
1601
437
    }
1602
7.80k
    ret->hour = temp;
1603
1604
    /* days */
1605
7.80k
    if (dt->day > MAX_DAYINMONTH(ret->year, ret->mon))
1606
8
        temp = MAX_DAYINMONTH(ret->year, ret->mon);
1607
7.80k
    else if (dt->day < 1)
1608
0
        temp = 1;
1609
7.80k
    else
1610
7.80k
        temp = dt->day;
1611
1612
7.80k
    temp += dur->day % DAYS_PER_EPOCH + carry;
1613
1614
1.14M
    while (1) {
1615
1.14M
        if (temp < 1) {
1616
161k
            if (ret->mon > 1) {
1617
144k
                ret->mon -= 1;
1618
144k
            }
1619
16.2k
            else {
1620
16.2k
                if (ret->year == YEAR_MIN) {
1621
0
                    exsltDateFreeDate(ret);
1622
0
                    return NULL;
1623
0
                }
1624
16.2k
                ret->mon   = 12;
1625
16.2k
                ret->year -= 1;
1626
16.2k
            }
1627
161k
            temp += MAX_DAYINMONTH(ret->year, ret->mon);
1628
978k
        } else if (temp > (long)MAX_DAYINMONTH(ret->year, ret->mon)) {
1629
971k
            temp -= MAX_DAYINMONTH(ret->year, ret->mon);
1630
971k
            if (ret->mon < 12) {
1631
890k
                ret->mon += 1;
1632
890k
            }
1633
81.0k
            else {
1634
81.0k
                if (ret->year == YEAR_MAX) {
1635
21
                    exsltDateFreeDate(ret);
1636
21
                    return NULL;
1637
21
                }
1638
81.0k
                ret->mon   = 1;
1639
81.0k
                ret->year += 1;
1640
81.0k
            }
1641
971k
        } else
1642
7.78k
            break;
1643
1.14M
    }
1644
1645
7.78k
    ret->day = temp;
1646
1647
    /*
1648
     * adjust the date/time type to the date values
1649
     */
1650
7.78k
    if (ret->type != XS_DATETIME) {
1651
5.09k
        if ((ret->hour) || (ret->min) || (ret->sec))
1652
1.04k
            ret->type = XS_DATETIME;
1653
4.05k
        else if (ret->type != XS_DATE) {
1654
2.42k
            if (ret->day != 1)
1655
1.45k
                ret->type = XS_DATE;
1656
968
            else if ((ret->type != XS_GYEARMONTH) && (ret->mon != 1))
1657
45
                ret->type = XS_GYEARMONTH;
1658
2.42k
        }
1659
5.09k
    }
1660
1661
7.78k
    return ret;
1662
7.80k
}
1663
1664
/**
1665
 * _exsltDateDifference:
1666
 * @x: an #exsltDateValPtr
1667
 * @y: an #exsltDateValPtr
1668
 * @flag: force difference in days
1669
 *
1670
 * Calculate the difference between @x and @y as a duration
1671
 * (i.e. y - x). If the @flag is set then even if the least specific
1672
 * format of @x or @y is xs:gYear or xs:gYearMonth.
1673
 *
1674
 * Returns a duration pointer or NULL.
1675
 */
1676
static exsltDateDurValPtr
1677
_exsltDateDifference (exsltDateValPtr x, exsltDateValPtr y, int flag)
1678
3.99k
{
1679
3.99k
    exsltDateDurValPtr ret;
1680
1681
3.99k
    if ((x == NULL) || (y == NULL))
1682
0
        return NULL;
1683
1684
3.99k
    if (((x->type < XS_GYEAR) || (x->type > XS_DATETIME)) ||
1685
3.99k
        ((y->type < XS_GYEAR) || (y->type > XS_DATETIME)))
1686
0
        return NULL;
1687
1688
    /*
1689
     * the operand with the most specific format must be converted to
1690
     * the same type as the operand with the least specific format.
1691
     */
1692
3.99k
    if (x->type != y->type) {
1693
2.28k
        if (x->type < y->type) {
1694
490
            _exsltDateTruncateDate(y, x->type);
1695
1.79k
        } else {
1696
1.79k
            _exsltDateTruncateDate(x, y->type);
1697
1.79k
        }
1698
2.28k
    }
1699
1700
3.99k
    ret = exsltDateCreateDuration();
1701
3.99k
    if (ret == NULL)
1702
6
        return NULL;
1703
1704
3.98k
    if (((x->type == XS_GYEAR) || (x->type == XS_GYEARMONTH)) && (!flag)) {
1705
        /* compute the difference in months */
1706
1.38k
        if ((x->year >= LONG_MAX / 24) || (x->year <= LONG_MIN / 24) ||
1707
1.38k
            (y->year >= LONG_MAX / 24) || (y->year <= LONG_MIN / 24)) {
1708
            /* Possible overflow. */
1709
278
            exsltDateFreeDuration(ret);
1710
278
            return NULL;
1711
278
        }
1712
1.10k
        ret->mon = (y->year - x->year) * 12 + (y->mon - x->mon);
1713
2.60k
    } else {
1714
2.60k
        long carry;
1715
1716
2.60k
        if ((x->year > LONG_MAX / 731) || (x->year < LONG_MIN / 731) ||
1717
2.60k
            (y->year > LONG_MAX / 731) || (y->year < LONG_MIN / 731)) {
1718
            /* Possible overflow. */
1719
27
            exsltDateFreeDuration(ret);
1720
27
            return NULL;
1721
27
        }
1722
1723
2.57k
        ret->sec  = TIME_TO_NUMBER(y) - TIME_TO_NUMBER(x);
1724
2.57k
        ret->sec += (x->tzo - y->tzo) * SECS_PER_MIN;
1725
2.57k
        carry    = (long)floor(ret->sec / SECS_PER_DAY);
1726
2.57k
        ret->sec  = ret->sec - carry * SECS_PER_DAY;
1727
1728
2.57k
        ret->day  = _exsltDateCastYMToDays(y) - _exsltDateCastYMToDays(x);
1729
2.57k
        ret->day += y->day - x->day;
1730
2.57k
        ret->day += carry;
1731
2.57k
    }
1732
1733
3.68k
    return ret;
1734
3.98k
}
1735
1736
/**
1737
 * _exsltDateAddDurCalc
1738
 * @ret: an exsltDateDurValPtr for the return value:
1739
 * @x: an exsltDateDurValPtr for the first operand
1740
 * @y: an exsltDateDurValPtr for the second operand
1741
 *
1742
 * Add two durations, catering for possible negative values.
1743
 * The sum is placed in @ret.
1744
 *
1745
 * Returns 1 for success, 0 if error detected.
1746
 */
1747
static int
1748
_exsltDateAddDurCalc (exsltDateDurValPtr ret, exsltDateDurValPtr x,
1749
          exsltDateDurValPtr y)
1750
10.1k
{
1751
    /* months */
1752
10.1k
    if ((x->mon > 0 && y->mon >  LONG_MAX - x->mon) ||
1753
10.1k
        (x->mon < 0 && y->mon <= LONG_MIN - x->mon)) {
1754
        /* Overflow */
1755
3
        return 0;
1756
3
    }
1757
10.1k
    ret->mon = x->mon + y->mon;
1758
1759
    /* days */
1760
10.1k
    if ((x->day > 0 && y->day >  LONG_MAX - x->day) ||
1761
10.1k
        (x->day < 0 && y->day <= LONG_MIN - x->day)) {
1762
        /* Overflow */
1763
144
        return 0;
1764
144
    }
1765
10.0k
    ret->day = x->day + y->day;
1766
1767
    /* seconds */
1768
10.0k
    ret->sec = x->sec + y->sec;
1769
10.0k
    if (ret->sec >= SECS_PER_DAY) {
1770
1.07k
        if (ret->day == LONG_MAX) {
1771
            /* Overflow */
1772
0
            return 0;
1773
0
        }
1774
1.07k
        ret->sec -= SECS_PER_DAY;
1775
1.07k
        ret->day += 1;
1776
1.07k
    }
1777
1778
    /*
1779
     * are the results indeterminate? i.e. how do you subtract days from
1780
     * months or years?
1781
     */
1782
10.0k
    if (ret->day >= 0) {
1783
7.53k
        if (((ret->day > 0) || (ret->sec > 0)) && (ret->mon < 0))
1784
546
            return 0;
1785
7.53k
    }
1786
2.47k
    else {
1787
2.47k
        if (ret->mon > 0)
1788
302
            return 0;
1789
2.47k
    }
1790
9.15k
    return 1;
1791
10.0k
}
1792
1793
/**
1794
 * _exsltDateAddDuration:
1795
 * @x: an #exsltDateDurValPtr
1796
 * @y: an #exsltDateDurValPtr
1797
 *
1798
 * Compute a new duration from @x and @y.
1799
 *
1800
 * Returns a duration pointer or NULL.
1801
 */
1802
static exsltDateDurValPtr
1803
_exsltDateAddDuration (exsltDateDurValPtr x, exsltDateDurValPtr y)
1804
2.98k
{
1805
2.98k
    exsltDateDurValPtr ret;
1806
1807
2.98k
    if ((x == NULL) || (y == NULL))
1808
0
        return NULL;
1809
1810
2.98k
    ret = exsltDateCreateDuration();
1811
2.98k
    if (ret == NULL)
1812
1
        return NULL;
1813
1814
2.97k
    if (_exsltDateAddDurCalc(ret, x, y))
1815
2.26k
        return ret;
1816
1817
719
    exsltDateFreeDuration(ret);
1818
719
    return NULL;
1819
2.97k
}
1820
1821
/****************************************************************
1822
 *                *
1823
 *    EXSLT - Dates and Times functions   *
1824
 *                *
1825
 ****************************************************************/
1826
1827
/**
1828
 * exsltDateDateTime:
1829
 *
1830
 * Implements the EXSLT - Dates and Times date-time() function:
1831
 *     string date:date-time()
1832
 *
1833
 * Returns the current date and time as a date/time string.
1834
 */
1835
static xmlChar *
1836
exsltDateDateTime (void)
1837
0
{
1838
0
    xmlChar *ret = NULL;
1839
0
    exsltDateValPtr cur;
1840
1841
0
    cur = exsltDateCurrent();
1842
0
    if (cur != NULL) {
1843
0
  ret = exsltDateFormatDateTime(cur);
1844
0
  exsltDateFreeDate(cur);
1845
0
    }
1846
1847
0
    return ret;
1848
0
}
1849
1850
/**
1851
 * exsltDateDate:
1852
 * @dateTime: a date/time string
1853
 *
1854
 * Implements the EXSLT - Dates and Times date() function:
1855
 *     string date:date (string?)
1856
 *
1857
 * Returns the date specified in the date/time string given as the
1858
 * argument.  If no argument is given, then the current local
1859
 * date/time, as returned by date:date-time is used as a default
1860
 * argument.
1861
 * The date/time string specified as an argument must be a string in
1862
 * the format defined as the lexical representation of either
1863
 * xs:dateTime or xs:date.  If the argument is not in either of these
1864
 * formats, returns NULL.
1865
 */
1866
static xmlChar *
1867
exsltDateDate (const xmlChar *dateTime)
1868
6.89k
{
1869
6.89k
    exsltDateValPtr dt = NULL;
1870
6.89k
    xmlChar *ret = NULL;
1871
1872
6.89k
    if (dateTime == NULL) {
1873
148
  dt = exsltDateCurrent();
1874
148
  if (dt == NULL)
1875
1
      return NULL;
1876
6.74k
    } else {
1877
6.74k
  dt = exsltDateParse(dateTime);
1878
6.74k
  if (dt == NULL)
1879
5.24k
      return NULL;
1880
1.49k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
1881
136
      exsltDateFreeDate(dt);
1882
136
      return NULL;
1883
136
  }
1884
1.49k
    }
1885
1886
1.50k
    ret = exsltDateFormatDate(dt);
1887
1.50k
    exsltDateFreeDate(dt);
1888
1889
1.50k
    return ret;
1890
6.89k
}
1891
1892
/**
1893
 * exsltDateTime:
1894
 * @dateTime: a date/time string
1895
 *
1896
 * Implements the EXSLT - Dates and Times time() function:
1897
 *     string date:time (string?)
1898
 *
1899
 * Returns the time specified in the date/time string given as the
1900
 * argument.  If no argument is given, then the current local
1901
 * date/time, as returned by date:date-time is used as a default
1902
 * argument.
1903
 * The date/time string specified as an argument must be a string in
1904
 * the format defined as the lexical representation of either
1905
 * xs:dateTime or xs:time.  If the argument is not in either of these
1906
 * formats, returns NULL.
1907
 */
1908
static xmlChar *
1909
exsltDateTime (const xmlChar *dateTime)
1910
11.8k
{
1911
11.8k
    exsltDateValPtr dt = NULL;
1912
11.8k
    xmlChar *ret = NULL;
1913
1914
11.8k
    if (dateTime == NULL) {
1915
252
  dt = exsltDateCurrent();
1916
252
  if (dt == NULL)
1917
1
      return NULL;
1918
11.5k
    } else {
1919
11.5k
  dt = exsltDateParse(dateTime);
1920
11.5k
  if (dt == NULL)
1921
6.75k
      return NULL;
1922
4.81k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) {
1923
1.43k
      exsltDateFreeDate(dt);
1924
1.43k
      return NULL;
1925
1.43k
  }
1926
4.81k
    }
1927
1928
3.63k
    ret = exsltDateFormatTime(dt);
1929
3.63k
    exsltDateFreeDate(dt);
1930
1931
3.63k
    return ret;
1932
11.8k
}
1933
1934
/**
1935
 * exsltDateYear:
1936
 * @dateTime: a date/time string
1937
 *
1938
 * Implements the EXSLT - Dates and Times year() function
1939
 *    number date:year (string?)
1940
 * Returns the year of a date as a number.  If no argument is given,
1941
 * then the current local date/time, as returned by date:date-time is
1942
 * used as a default argument.
1943
 * The date/time string specified as the first argument must be a
1944
 * right-truncated string in the format defined as the lexical
1945
 * representation of xs:dateTime in one of the formats defined in [XML
1946
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
1947
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
1948
 *  - xs:date (CCYY-MM-DD)
1949
 *  - xs:gYearMonth (CCYY-MM)
1950
 *  - xs:gYear (CCYY)
1951
 * If the date/time string is not in one of these formats, then NaN is
1952
 * returned.
1953
 */
1954
static double
1955
exsltDateYear (const xmlChar *dateTime)
1956
10.9k
{
1957
10.9k
    exsltDateValPtr dt;
1958
10.9k
    long year;
1959
10.9k
    double ret;
1960
1961
10.9k
    if (dateTime == NULL) {
1962
200
  dt = exsltDateCurrent();
1963
200
  if (dt == NULL)
1964
1
      return NAN;
1965
10.7k
    } else {
1966
10.7k
  dt = exsltDateParse(dateTime);
1967
10.7k
  if (dt == NULL)
1968
5.13k
      return NAN;
1969
5.62k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) &&
1970
5.62k
      (dt->type != XS_GYEARMONTH) && (dt->type != XS_GYEAR)) {
1971
1.29k
      exsltDateFreeDate(dt);
1972
1.29k
      return NAN;
1973
1.29k
  }
1974
5.62k
    }
1975
1976
4.53k
    year = dt->year;
1977
4.53k
    if (year <= 0) year -= 1; /* Adjust for missing year 0. */
1978
4.53k
    ret = (double) year;
1979
4.53k
    exsltDateFreeDate(dt);
1980
1981
4.53k
    return ret;
1982
10.9k
}
1983
1984
/**
1985
 * exsltDateLeapYear:
1986
 * @dateTime: a date/time string
1987
 *
1988
 * Implements the EXSLT - Dates and Times leap-year() function:
1989
 *    boolean date:leap-yea (string?)
1990
 * Returns true if the year given in a date is a leap year.  If no
1991
 * argument is given, then the current local date/time, as returned by
1992
 * date:date-time is used as a default argument.
1993
 * The date/time string specified as the first argument must be a
1994
 * right-truncated string in the format defined as the lexical
1995
 * representation of xs:dateTime in one of the formats defined in [XML
1996
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
1997
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
1998
 *  - xs:date (CCYY-MM-DD)
1999
 *  - xs:gYearMonth (CCYY-MM)
2000
 *  - xs:gYear (CCYY)
2001
 * If the date/time string is not in one of these formats, then NaN is
2002
 * returned.
2003
 */
2004
static xmlXPathObjectPtr
2005
exsltDateLeapYear (const xmlChar *dateTime)
2006
8.15k
{
2007
8.15k
    exsltDateValPtr dt = NULL;
2008
8.15k
    xmlXPathObjectPtr ret;
2009
2010
8.15k
    if (dateTime == NULL) {
2011
125
  dt = exsltDateCurrent();
2012
8.02k
    } else {
2013
8.02k
  dt = exsltDateParse(dateTime);
2014
8.02k
  if ((dt != NULL) &&
2015
8.02k
            (dt->type != XS_DATETIME) && (dt->type != XS_DATE) &&
2016
8.02k
      (dt->type != XS_GYEARMONTH) && (dt->type != XS_GYEAR)) {
2017
1.20k
      exsltDateFreeDate(dt);
2018
1.20k
      dt = NULL;
2019
1.20k
  }
2020
8.02k
    }
2021
2022
8.15k
    if (dt == NULL) {
2023
4.21k
        ret = xmlXPathNewFloat(NAN);
2024
4.21k
    }
2025
3.93k
    else {
2026
3.93k
        ret = xmlXPathNewBoolean(IS_LEAP(dt->year));
2027
3.93k
        exsltDateFreeDate(dt);
2028
3.93k
    }
2029
2030
8.15k
    return ret;
2031
8.15k
}
2032
2033
/**
2034
 * exsltDateMonthInYear:
2035
 * @dateTime: a date/time string
2036
 *
2037
 * Implements the EXSLT - Dates and Times month-in-year() function:
2038
 *    number date:month-in-year (string?)
2039
 * Returns the month of a date as a number.  If no argument is given,
2040
 * then the current local date/time, as returned by date:date-time is
2041
 * used the default argument.
2042
 * The date/time string specified as the argument is a left or
2043
 * right-truncated string in the format defined as the lexical
2044
 * representation of xs:dateTime in one of the formats defined in [XML
2045
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2046
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2047
 *  - xs:date (CCYY-MM-DD)
2048
 *  - xs:gYearMonth (CCYY-MM)
2049
 *  - xs:gMonth (--MM--)
2050
 *  - xs:gMonthDay (--MM-DD)
2051
 * If the date/time string is not in one of these formats, then NaN is
2052
 * returned.
2053
 */
2054
static double
2055
exsltDateMonthInYear (const xmlChar *dateTime)
2056
28.4k
{
2057
28.4k
    exsltDateValPtr dt;
2058
28.4k
    double ret;
2059
2060
28.4k
    if (dateTime == NULL) {
2061
327
  dt = exsltDateCurrent();
2062
327
  if (dt == NULL)
2063
3
      return NAN;
2064
28.1k
    } else {
2065
28.1k
  dt = exsltDateParse(dateTime);
2066
28.1k
  if (dt == NULL)
2067
11.4k
      return NAN;
2068
16.7k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) &&
2069
16.7k
      (dt->type != XS_GYEARMONTH) && (dt->type != XS_GMONTH) &&
2070
16.7k
      (dt->type != XS_GMONTHDAY)) {
2071
1.42k
      exsltDateFreeDate(dt);
2072
1.42k
      return NAN;
2073
1.42k
  }
2074
16.7k
    }
2075
2076
15.6k
    ret = (double) dt->mon;
2077
15.6k
    exsltDateFreeDate(dt);
2078
2079
15.6k
    return ret;
2080
28.4k
}
2081
2082
/**
2083
 * exsltDateMonthName:
2084
 * @dateTime: a date/time string
2085
 *
2086
 * Implements the EXSLT - Dates and Time month-name() function
2087
 *    string date:month-name (string?)
2088
 * Returns the full name of the month of a date.  If no argument is
2089
 * given, then the current local date/time, as returned by
2090
 * date:date-time is used the default argument.
2091
 * The date/time string specified as the argument is a left or
2092
 * right-truncated string in the format defined as the lexical
2093
 * representation of xs:dateTime in one of the formats defined in [XML
2094
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2095
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2096
 *  - xs:date (CCYY-MM-DD)
2097
 *  - xs:gYearMonth (CCYY-MM)
2098
 *  - xs:gMonth (--MM--)
2099
 * If the date/time string is not in one of these formats, then an
2100
 * empty string ('') is returned.
2101
 * The result is an English month name: one of 'January', 'February',
2102
 * 'March', 'April', 'May', 'June', 'July', 'August', 'September',
2103
 * 'October', 'November' or 'December'.
2104
 */
2105
static const xmlChar *
2106
exsltDateMonthName (const xmlChar *dateTime)
2107
9.16k
{
2108
9.16k
    static const xmlChar monthNames[13][10] = {
2109
9.16k
        { 0 },
2110
9.16k
  { 'J', 'a', 'n', 'u', 'a', 'r', 'y', 0 },
2111
9.16k
  { 'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y', 0 },
2112
9.16k
  { 'M', 'a', 'r', 'c', 'h', 0 },
2113
9.16k
  { 'A', 'p', 'r', 'i', 'l', 0 },
2114
9.16k
  { 'M', 'a', 'y', 0 },
2115
9.16k
  { 'J', 'u', 'n', 'e', 0 },
2116
9.16k
  { 'J', 'u', 'l', 'y', 0 },
2117
9.16k
  { 'A', 'u', 'g', 'u', 's', 't', 0 },
2118
9.16k
  { 'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', 0 },
2119
9.16k
  { 'O', 'c', 't', 'o', 'b', 'e', 'r', 0 },
2120
9.16k
  { 'N', 'o', 'v', 'e', 'm', 'b', 'e', 'r', 0 },
2121
9.16k
  { 'D', 'e', 'c', 'e', 'm', 'b', 'e', 'r', 0 }
2122
9.16k
    };
2123
9.16k
    double month;
2124
9.16k
    int index = 0;
2125
9.16k
    month = exsltDateMonthInYear(dateTime);
2126
9.16k
    if (!xmlXPathIsNaN(month) && (month >= 1.0) && (month <= 12.0))
2127
4.67k
      index = (int) month;
2128
9.16k
    return monthNames[index];
2129
9.16k
}
2130
2131
/**
2132
 * exsltDateMonthAbbreviation:
2133
 * @dateTime: a date/time string
2134
 *
2135
 * Implements the EXSLT - Dates and Time month-abbreviation() function
2136
 *    string date:month-abbreviation (string?)
2137
 * Returns the abbreviation of the month of a date.  If no argument is
2138
 * given, then the current local date/time, as returned by
2139
 * date:date-time is used the default argument.
2140
 * The date/time string specified as the argument is a left or
2141
 * right-truncated string in the format defined as the lexical
2142
 * representation of xs:dateTime in one of the formats defined in [XML
2143
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2144
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2145
 *  - xs:date (CCYY-MM-DD)
2146
 *  - xs:gYearMonth (CCYY-MM)
2147
 *  - xs:gMonth (--MM--)
2148
 * If the date/time string is not in one of these formats, then an
2149
 * empty string ('') is returned.
2150
 * The result is an English month abbreviation: one of 'Jan', 'Feb',
2151
 * 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov' or
2152
 * 'Dec'.
2153
 */
2154
static const xmlChar *
2155
exsltDateMonthAbbreviation (const xmlChar *dateTime)
2156
9.66k
{
2157
9.66k
    static const xmlChar monthAbbreviations[13][4] = {
2158
9.66k
        { 0 },
2159
9.66k
  { 'J', 'a', 'n', 0 },
2160
9.66k
  { 'F', 'e', 'b', 0 },
2161
9.66k
  { 'M', 'a', 'r', 0 },
2162
9.66k
  { 'A', 'p', 'r', 0 },
2163
9.66k
  { 'M', 'a', 'y', 0 },
2164
9.66k
  { 'J', 'u', 'n', 0 },
2165
9.66k
  { 'J', 'u', 'l', 0 },
2166
9.66k
  { 'A', 'u', 'g', 0 },
2167
9.66k
  { 'S', 'e', 'p', 0 },
2168
9.66k
  { 'O', 'c', 't', 0 },
2169
9.66k
  { 'N', 'o', 'v', 0 },
2170
9.66k
  { 'D', 'e', 'c', 0 }
2171
9.66k
    };
2172
9.66k
    double month;
2173
9.66k
    int index = 0;
2174
9.66k
    month = exsltDateMonthInYear(dateTime);
2175
9.66k
    if (!xmlXPathIsNaN(month) && (month >= 1.0) && (month <= 12.0))
2176
6.49k
      index = (int) month;
2177
9.66k
    return monthAbbreviations[index];
2178
9.66k
}
2179
2180
/**
2181
 * exsltDateWeekInYear:
2182
 * @dateTime: a date/time string
2183
 *
2184
 * Implements the EXSLT - Dates and Times week-in-year() function
2185
 *    number date:week-in-year (string?)
2186
 * Returns the week of the year as a number.  If no argument is given,
2187
 * then the current local date/time, as returned by date:date-time is
2188
 * used as the default argument.  For the purposes of numbering,
2189
 * counting follows ISO 8601: week 1 in a year is the week containing
2190
 * the first Thursday of the year, with new weeks beginning on a
2191
 * Monday.
2192
 * The date/time string specified as the argument is a right-truncated
2193
 * string in the format defined as the lexical representation of
2194
 * xs:dateTime in one of the formats defined in [XML Schema Part 2:
2195
 * Datatypes].  The permitted formats are as follows:
2196
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2197
 *  - xs:date (CCYY-MM-DD)
2198
 * If the date/time string is not in one of these formats, then NaN is
2199
 * returned.
2200
 */
2201
static double
2202
exsltDateWeekInYear (const xmlChar *dateTime)
2203
14.6k
{
2204
14.6k
    exsltDateValPtr dt;
2205
14.6k
    long diy, diw, year, ret;
2206
2207
14.6k
    if (dateTime == NULL) {
2208
296
  dt = exsltDateCurrent();
2209
296
  if (dt == NULL)
2210
1
      return NAN;
2211
14.3k
    } else {
2212
14.3k
  dt = exsltDateParse(dateTime);
2213
14.3k
  if (dt == NULL)
2214
5.53k
      return NAN;
2215
8.77k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2216
862
      exsltDateFreeDate(dt);
2217
862
      return NAN;
2218
862
  }
2219
8.77k
    }
2220
2221
8.20k
    diy = DAY_IN_YEAR(dt->day, dt->mon, dt->year);
2222
2223
    /*
2224
     * Determine day-in-week (0=Sun, 1=Mon, etc.) then adjust so Monday
2225
     * is the first day-in-week
2226
     */
2227
8.20k
    diw = (_exsltDateDayInWeek(diy, dt->year) + 6) % 7;
2228
2229
    /* ISO 8601 adjustment, 3 is Thu */
2230
8.20k
    diy += (3 - diw);
2231
8.20k
    if(diy < 1) {
2232
1.20k
  year = dt->year - 1;
2233
1.20k
  if(year == 0) year--;
2234
1.20k
  diy = DAY_IN_YEAR(31, 12, year) + diy;
2235
7.00k
    } else if (diy > (long)DAY_IN_YEAR(31, 12, dt->year)) {
2236
3.50k
  diy -= DAY_IN_YEAR(31, 12, dt->year);
2237
3.50k
    }
2238
2239
8.20k
    ret = ((diy - 1) / 7) + 1;
2240
2241
8.20k
    exsltDateFreeDate(dt);
2242
2243
8.20k
    return (double) ret;
2244
14.6k
}
2245
2246
/**
2247
 * exsltDateWeekInMonth:
2248
 * @dateTime: a date/time string
2249
 *
2250
 * Implements the EXSLT - Dates and Times week-in-month() function
2251
 *    number date:week-in-month (string?)
2252
 * The date:week-in-month function returns the week in a month of a
2253
 * date as a number. If no argument is given, then the current local
2254
 * date/time, as returned by date:date-time is used the default
2255
 * argument. For the purposes of numbering, the first day of the month
2256
 * is in week 1 and new weeks begin on a Monday (so the first and last
2257
 * weeks in a month will often have less than 7 days in them).
2258
 * The date/time string specified as the argument is a right-truncated
2259
 * string in the format defined as the lexical representation of
2260
 * xs:dateTime in one of the formats defined in [XML Schema Part 2:
2261
 * Datatypes].  The permitted formats are as follows:
2262
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2263
 *  - xs:date (CCYY-MM-DD)
2264
 * If the date/time string is not in one of these formats, then NaN is
2265
 * returned.
2266
 */
2267
static double
2268
exsltDateWeekInMonth (const xmlChar *dateTime)
2269
3.01k
{
2270
3.01k
    exsltDateValPtr dt;
2271
3.01k
    long fdiy, fdiw, ret;
2272
2273
3.01k
    if (dateTime == NULL) {
2274
52
  dt = exsltDateCurrent();
2275
52
  if (dt == NULL)
2276
1
      return NAN;
2277
2.95k
    } else {
2278
2.95k
  dt = exsltDateParse(dateTime);
2279
2.95k
  if (dt == NULL)
2280
2.11k
      return NAN;
2281
840
  if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2282
80
      exsltDateFreeDate(dt);
2283
80
      return NAN;
2284
80
  }
2285
840
    }
2286
2287
811
    fdiy = DAY_IN_YEAR(1, dt->mon, dt->year);
2288
    /*
2289
     * Determine day-in-week (0=Sun, 1=Mon, etc.) then adjust so Monday
2290
     * is the first day-in-week
2291
     */
2292
811
    fdiw = (_exsltDateDayInWeek(fdiy, dt->year) + 6) % 7;
2293
2294
811
    ret = ((dt->day + fdiw - 1) / 7) + 1;
2295
2296
811
    exsltDateFreeDate(dt);
2297
2298
811
    return (double) ret;
2299
3.01k
}
2300
2301
/**
2302
 * exsltDateDayInYear:
2303
 * @dateTime: a date/time string
2304
 *
2305
 * Implements the EXSLT - Dates and Times day-in-year() function
2306
 *    number date:day-in-year (string?)
2307
 * Returns the day of a date in a year as a number.  If no argument is
2308
 * given, then the current local date/time, as returned by
2309
 * date:date-time is used the default argument.
2310
 * The date/time string specified as the argument is a right-truncated
2311
 * string in the format defined as the lexical representation of
2312
 * xs:dateTime in one of the formats defined in [XML Schema Part 2:
2313
 * Datatypes].  The permitted formats are as follows:
2314
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2315
 *  - xs:date (CCYY-MM-DD)
2316
 * If the date/time string is not in one of these formats, then NaN is
2317
 * returned.
2318
 */
2319
static double
2320
exsltDateDayInYear (const xmlChar *dateTime)
2321
11.5k
{
2322
11.5k
    exsltDateValPtr dt;
2323
11.5k
    long ret;
2324
2325
11.5k
    if (dateTime == NULL) {
2326
282
  dt = exsltDateCurrent();
2327
282
  if (dt == NULL)
2328
1
      return NAN;
2329
11.2k
    } else {
2330
11.2k
  dt = exsltDateParse(dateTime);
2331
11.2k
  if (dt == NULL)
2332
3.64k
      return NAN;
2333
7.60k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2334
572
      exsltDateFreeDate(dt);
2335
572
      return NAN;
2336
572
  }
2337
7.60k
    }
2338
2339
7.31k
    ret = DAY_IN_YEAR(dt->day, dt->mon, dt->year);
2340
2341
7.31k
    exsltDateFreeDate(dt);
2342
2343
7.31k
    return (double) ret;
2344
11.5k
}
2345
2346
/**
2347
 * exsltDateDayInMonth:
2348
 * @dateTime: a date/time string
2349
 *
2350
 * Implements the EXSLT - Dates and Times day-in-month() function:
2351
 *    number date:day-in-month (string?)
2352
 * Returns the day of a date as a number.  If no argument is given,
2353
 * then the current local date/time, as returned by date:date-time is
2354
 * used the default argument.
2355
 * The date/time string specified as the argument is a left or
2356
 * right-truncated string in the format defined as the lexical
2357
 * representation of xs:dateTime in one of the formats defined in [XML
2358
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2359
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2360
 *  - xs:date (CCYY-MM-DD)
2361
 *  - xs:gMonthDay (--MM-DD)
2362
 *  - xs:gDay (---DD)
2363
 * If the date/time string is not in one of these formats, then NaN is
2364
 * returned.
2365
 */
2366
static double
2367
exsltDateDayInMonth (const xmlChar *dateTime)
2368
10.9k
{
2369
10.9k
    exsltDateValPtr dt;
2370
10.9k
    double ret;
2371
2372
10.9k
    if (dateTime == NULL) {
2373
263
  dt = exsltDateCurrent();
2374
263
  if (dt == NULL)
2375
1
      return NAN;
2376
10.6k
    } else {
2377
10.6k
  dt = exsltDateParse(dateTime);
2378
10.6k
  if (dt == NULL)
2379
3.00k
      return NAN;
2380
7.69k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) &&
2381
7.69k
      (dt->type != XS_GMONTHDAY) && (dt->type != XS_GDAY)) {
2382
835
      exsltDateFreeDate(dt);
2383
835
      return NAN;
2384
835
  }
2385
7.69k
    }
2386
2387
7.12k
    ret = (double) dt->day;
2388
7.12k
    exsltDateFreeDate(dt);
2389
2390
7.12k
    return ret;
2391
10.9k
}
2392
2393
/**
2394
 * exsltDateDayOfWeekInMonth:
2395
 * @dateTime: a date/time string
2396
 *
2397
 * Implements the EXSLT - Dates and Times day-of-week-in-month() function:
2398
 *    number date:day-of-week-in-month (string?)
2399
 * Returns the day-of-the-week in a month of a date as a number
2400
 * (e.g. 3 for the 3rd Tuesday in May).  If no argument is
2401
 * given, then the current local date/time, as returned by
2402
 * date:date-time is used the default argument.
2403
 * The date/time string specified as the argument is a right-truncated
2404
 * string in the format defined as the lexical representation of
2405
 * xs:dateTime in one of the formats defined in [XML Schema Part 2:
2406
 * Datatypes].  The permitted formats are as follows:
2407
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2408
 *  - xs:date (CCYY-MM-DD)
2409
 * If the date/time string is not in one of these formats, then NaN is
2410
 * returned.
2411
 */
2412
static double
2413
exsltDateDayOfWeekInMonth (const xmlChar *dateTime)
2414
9.69k
{
2415
9.69k
    exsltDateValPtr dt;
2416
9.69k
    long ret;
2417
2418
9.69k
    if (dateTime == NULL) {
2419
74
  dt = exsltDateCurrent();
2420
74
  if (dt == NULL)
2421
1
      return NAN;
2422
9.61k
    } else {
2423
9.61k
  dt = exsltDateParse(dateTime);
2424
9.61k
  if (dt == NULL)
2425
2.57k
      return NAN;
2426
7.04k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2427
1.23k
      exsltDateFreeDate(dt);
2428
1.23k
      return NAN;
2429
1.23k
  }
2430
7.04k
    }
2431
2432
5.88k
    ret = ((dt->day -1) / 7) + 1;
2433
2434
5.88k
    exsltDateFreeDate(dt);
2435
2436
5.88k
    return (double) ret;
2437
9.69k
}
2438
2439
/**
2440
 * exsltDateDayInWeek:
2441
 * @dateTime: a date/time string
2442
 *
2443
 * Implements the EXSLT - Dates and Times day-in-week() function:
2444
 *    number date:day-in-week (string?)
2445
 * Returns the day of the week given in a date as a number.  If no
2446
 * argument is given, then the current local date/time, as returned by
2447
 * date:date-time is used the default argument.
2448
 * The date/time string specified as the argument is a left or
2449
 * right-truncated string in the format defined as the lexical
2450
 * representation of xs:dateTime in one of the formats defined in [XML
2451
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2452
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2453
 *  - xs:date (CCYY-MM-DD)
2454
 * If the date/time string is not in one of these formats, then NaN is
2455
 * returned.
2456
 * The numbering of days of the week starts at 1 for Sunday, 2 for
2457
 * Monday and so on up to 7 for Saturday.
2458
 */
2459
static double
2460
exsltDateDayInWeek (const xmlChar *dateTime)
2461
24.2k
{
2462
24.2k
    exsltDateValPtr dt;
2463
24.2k
    long diy, ret;
2464
2465
24.2k
    if (dateTime == NULL) {
2466
508
  dt = exsltDateCurrent();
2467
508
  if (dt == NULL)
2468
1
      return NAN;
2469
23.7k
    } else {
2470
23.7k
  dt = exsltDateParse(dateTime);
2471
23.7k
  if (dt == NULL)
2472
8.33k
      return NAN;
2473
15.4k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2474
2.55k
      exsltDateFreeDate(dt);
2475
2.55k
      return NAN;
2476
2.55k
  }
2477
15.4k
    }
2478
2479
13.4k
    diy = DAY_IN_YEAR(dt->day, dt->mon, dt->year);
2480
2481
13.4k
    ret = _exsltDateDayInWeek(diy, dt->year) + 1;
2482
2483
13.4k
    exsltDateFreeDate(dt);
2484
2485
13.4k
    return (double) ret;
2486
24.2k
}
2487
2488
/**
2489
 * exsltDateDayName:
2490
 * @dateTime: a date/time string
2491
 *
2492
 * Implements the EXSLT - Dates and Time day-name() function
2493
 *    string date:day-name (string?)
2494
 * Returns the full name of the day of the week of a date.  If no
2495
 * argument is given, then the current local date/time, as returned by
2496
 * date:date-time is used the default argument.
2497
 * The date/time string specified as the argument is a left or
2498
 * right-truncated string in the format defined as the lexical
2499
 * representation of xs:dateTime in one of the formats defined in [XML
2500
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2501
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2502
 *  - xs:date (CCYY-MM-DD)
2503
 * If the date/time string is not in one of these formats, then an
2504
 * empty string ('') is returned.
2505
 * The result is an English day name: one of 'Sunday', 'Monday',
2506
 * 'Tuesday', 'Wednesday', 'Thursday' or 'Friday'.
2507
 */
2508
static const xmlChar *
2509
exsltDateDayName (const xmlChar *dateTime)
2510
7.66k
{
2511
7.66k
    static const xmlChar dayNames[8][10] = {
2512
7.66k
        { 0 },
2513
7.66k
  { 'S', 'u', 'n', 'd', 'a', 'y', 0 },
2514
7.66k
  { 'M', 'o', 'n', 'd', 'a', 'y', 0 },
2515
7.66k
  { 'T', 'u', 'e', 's', 'd', 'a', 'y', 0 },
2516
7.66k
  { 'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', 0 },
2517
7.66k
  { 'T', 'h', 'u', 'r', 's', 'd', 'a', 'y', 0 },
2518
7.66k
  { 'F', 'r', 'i', 'd', 'a', 'y', 0 },
2519
7.66k
  { 'S', 'a', 't', 'u', 'r', 'd', 'a', 'y', 0 }
2520
7.66k
    };
2521
7.66k
    double day;
2522
7.66k
    int index = 0;
2523
7.66k
    day = exsltDateDayInWeek(dateTime);
2524
7.66k
    if(!xmlXPathIsNaN(day) && (day >= 1.0) && (day <= 7.0))
2525
3.96k
      index = (int) day;
2526
7.66k
    return dayNames[index];
2527
7.66k
}
2528
2529
/**
2530
 * exsltDateDayAbbreviation:
2531
 * @dateTime: a date/time string
2532
 *
2533
 * Implements the EXSLT - Dates and Time day-abbreviation() function
2534
 *    string date:day-abbreviation (string?)
2535
 * Returns the abbreviation of the day of the week of a date.  If no
2536
 * argument is given, then the current local date/time, as returned by
2537
 * date:date-time is used the default argument.
2538
 * The date/time string specified as the argument is a left or
2539
 * right-truncated string in the format defined as the lexical
2540
 * representation of xs:dateTime in one of the formats defined in [XML
2541
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2542
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2543
 *  - xs:date (CCYY-MM-DD)
2544
 * If the date/time string is not in one of these formats, then an
2545
 * empty string ('') is returned.
2546
 * The result is a three-letter English day abbreviation: one of
2547
 * 'Sun', 'Mon', 'Tue', 'Wed', 'Thu' or 'Fri'.
2548
 */
2549
static const xmlChar *
2550
exsltDateDayAbbreviation (const xmlChar *dateTime)
2551
6.83k
{
2552
6.83k
    static const xmlChar dayAbbreviations[8][4] = {
2553
6.83k
        { 0 },
2554
6.83k
  { 'S', 'u', 'n', 0 },
2555
6.83k
  { 'M', 'o', 'n', 0 },
2556
6.83k
  { 'T', 'u', 'e', 0 },
2557
6.83k
  { 'W', 'e', 'd', 0 },
2558
6.83k
  { 'T', 'h', 'u', 0 },
2559
6.83k
  { 'F', 'r', 'i', 0 },
2560
6.83k
  { 'S', 'a', 't', 0 }
2561
6.83k
    };
2562
6.83k
    double day;
2563
6.83k
    int index = 0;
2564
6.83k
    day = exsltDateDayInWeek(dateTime);
2565
6.83k
    if(!xmlXPathIsNaN(day) && (day >= 1.0) && (day <= 7.0))
2566
3.53k
      index = (int) day;
2567
6.83k
    return dayAbbreviations[index];
2568
6.83k
}
2569
2570
/**
2571
 * exsltDateHourInDay:
2572
 * @dateTime: a date/time string
2573
 *
2574
 * Implements the EXSLT - Dates and Times day-in-month() function:
2575
 *    number date:day-in-month (string?)
2576
 * Returns the hour of the day as a number.  If no argument is given,
2577
 * then the current local date/time, as returned by date:date-time is
2578
 * used the default argument.
2579
 * The date/time string specified as the argument is a left or
2580
 * right-truncated string in the format defined as the lexical
2581
 * representation of xs:dateTime in one of the formats defined in [XML
2582
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2583
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2584
 *  - xs:time (hh:mm:ss)
2585
 * If the date/time string is not in one of these formats, then NaN is
2586
 * returned.
2587
 */
2588
static double
2589
exsltDateHourInDay (const xmlChar *dateTime)
2590
10.3k
{
2591
10.3k
    exsltDateValPtr dt;
2592
10.3k
    double ret;
2593
2594
10.3k
    if (dateTime == NULL) {
2595
140
  dt = exsltDateCurrent();
2596
140
  if (dt == NULL)
2597
1
      return NAN;
2598
10.1k
    } else {
2599
10.1k
  dt = exsltDateParse(dateTime);
2600
10.1k
  if (dt == NULL)
2601
3.84k
      return NAN;
2602
6.34k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) {
2603
1.65k
      exsltDateFreeDate(dt);
2604
1.65k
      return NAN;
2605
1.65k
  }
2606
6.34k
    }
2607
2608
4.82k
    ret = (double) dt->hour;
2609
4.82k
    exsltDateFreeDate(dt);
2610
2611
4.82k
    return ret;
2612
10.3k
}
2613
2614
/**
2615
 * exsltDateMinuteInHour:
2616
 * @dateTime: a date/time string
2617
 *
2618
 * Implements the EXSLT - Dates and Times day-in-month() function:
2619
 *    number date:day-in-month (string?)
2620
 * Returns the minute of the hour as a number.  If no argument is
2621
 * given, then the current local date/time, as returned by
2622
 * date:date-time is used the default argument.
2623
 * The date/time string specified as the argument is a left or
2624
 * right-truncated string in the format defined as the lexical
2625
 * representation of xs:dateTime in one of the formats defined in [XML
2626
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2627
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2628
 *  - xs:time (hh:mm:ss)
2629
 * If the date/time string is not in one of these formats, then NaN is
2630
 * returned.
2631
 */
2632
static double
2633
exsltDateMinuteInHour (const xmlChar *dateTime)
2634
12.9k
{
2635
12.9k
    exsltDateValPtr dt;
2636
12.9k
    double ret;
2637
2638
12.9k
    if (dateTime == NULL) {
2639
221
  dt = exsltDateCurrent();
2640
221
  if (dt == NULL)
2641
1
      return NAN;
2642
12.7k
    } else {
2643
12.7k
  dt = exsltDateParse(dateTime);
2644
12.7k
  if (dt == NULL)
2645
4.87k
      return NAN;
2646
7.85k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) {
2647
3.01k
      exsltDateFreeDate(dt);
2648
3.01k
      return NAN;
2649
3.01k
  }
2650
7.85k
    }
2651
2652
5.06k
    ret = (double) dt->min;
2653
5.06k
    exsltDateFreeDate(dt);
2654
2655
5.06k
    return ret;
2656
12.9k
}
2657
2658
/**
2659
 * exsltDateSecondInMinute:
2660
 * @dateTime: a date/time string
2661
 *
2662
 * Implements the EXSLT - Dates and Times second-in-minute() function:
2663
 *    number date:day-in-month (string?)
2664
 * Returns the second of the minute as a number.  If no argument is
2665
 * given, then the current local date/time, as returned by
2666
 * date:date-time is used the default argument.
2667
 * The date/time string specified as the argument is a left or
2668
 * right-truncated string in the format defined as the lexical
2669
 * representation of xs:dateTime in one of the formats defined in [XML
2670
 * Schema Part 2: Datatypes].  The permitted formats are as follows:
2671
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2672
 *  - xs:time (hh:mm:ss)
2673
 * If the date/time string is not in one of these formats, then NaN is
2674
 * returned.
2675
 *
2676
 * Returns the second or NaN.
2677
 */
2678
static double
2679
exsltDateSecondInMinute (const xmlChar *dateTime)
2680
13.9k
{
2681
13.9k
    exsltDateValPtr dt;
2682
13.9k
    double ret;
2683
2684
13.9k
    if (dateTime == NULL) {
2685
131
  dt = exsltDateCurrent();
2686
131
  if (dt == NULL)
2687
1
      return NAN;
2688
13.8k
    } else {
2689
13.8k
  dt = exsltDateParse(dateTime);
2690
13.8k
  if (dt == NULL)
2691
5.98k
      return NAN;
2692
7.87k
  if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) {
2693
3.53k
      exsltDateFreeDate(dt);
2694
3.53k
      return NAN;
2695
3.53k
  }
2696
7.87k
    }
2697
2698
4.47k
    ret = dt->sec;
2699
4.47k
    exsltDateFreeDate(dt);
2700
2701
4.47k
    return ret;
2702
13.9k
}
2703
2704
/**
2705
 * exsltDateAdd:
2706
 * @xstr: date/time string
2707
 * @ystr: date/time string
2708
 *
2709
 * Implements the date:add (string,string) function which returns the
2710
 * date/time * resulting from adding a duration to a date/time.
2711
 * The first argument (@xstr) must be right-truncated date/time
2712
 * strings in one of the formats defined in [XML Schema Part 2:
2713
 * Datatypes]. The permitted formats are as follows:
2714
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2715
 *  - xs:date (CCYY-MM-DD)
2716
 *  - xs:gYearMonth (CCYY-MM)
2717
 *  - xs:gYear (CCYY)
2718
 * The second argument (@ystr) is a string in the format defined for
2719
 * xs:duration in [3.2.6 duration] of [XML Schema Part 2: Datatypes].
2720
 * The return value is a right-truncated date/time strings in one of
2721
 * the formats defined in [XML Schema Part 2: Datatypes] and listed
2722
 * above. This value is calculated using the algorithm described in
2723
 * [Appendix E Adding durations to dateTimes] of [XML Schema Part 2:
2724
 * Datatypes].
2725
2726
 * Returns date/time string or NULL.
2727
 */
2728
static xmlChar *
2729
exsltDateAdd (const xmlChar *xstr, const xmlChar *ystr)
2730
16.3k
{
2731
16.3k
    exsltDateValPtr dt, res;
2732
16.3k
    exsltDateDurValPtr dur;
2733
16.3k
    xmlChar     *ret;
2734
2735
16.3k
    if ((xstr == NULL) || (ystr == NULL))
2736
0
        return NULL;
2737
2738
16.3k
    dt = exsltDateParse(xstr);
2739
16.3k
    if (dt == NULL)
2740
7.47k
        return NULL;
2741
8.92k
    else if ((dt->type < XS_GYEAR) || (dt->type > XS_DATETIME)) {
2742
76
        exsltDateFreeDate(dt);
2743
76
        return NULL;
2744
76
    }
2745
2746
8.84k
    dur = exsltDateParseDuration(ystr);
2747
8.84k
    if (dur == NULL) {
2748
842
        exsltDateFreeDate(dt);
2749
842
        return NULL;
2750
842
    }
2751
2752
8.00k
    res = _exsltDateAdd(dt, dur);
2753
2754
8.00k
    exsltDateFreeDate(dt);
2755
8.00k
    exsltDateFreeDuration(dur);
2756
2757
8.00k
    if (res == NULL)
2758
215
        return NULL;
2759
2760
7.78k
    ret = exsltDateFormat(res);
2761
7.78k
    exsltDateFreeDate(res);
2762
2763
7.78k
    return ret;
2764
8.00k
}
2765
2766
/**
2767
 * exsltDateAddDuration:
2768
 * @xstr:      first duration string
2769
 * @ystr:      second duration string
2770
 *
2771
 * Implements the date:add-duration (string,string) function which returns
2772
 * the duration resulting from adding two durations together.
2773
 * Both arguments are strings in the format defined for xs:duration
2774
 * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. If either
2775
 * argument is not in this format, the function returns an empty string
2776
 * ('').
2777
 * The return value is a string in the format defined for xs:duration
2778
 * in [3.2.6 duration] of [XML Schema Part 2: Datatypes].
2779
 * The durations can usually be added by summing the numbers given for
2780
 * each of the components in the durations. However, if the durations
2781
 * are differently signed, then this sometimes results in durations
2782
 * that are impossible to express in this syntax (e.g. 'P1M' + '-P1D').
2783
 * In these cases, the function returns an empty string ('').
2784
 *
2785
 * Returns duration string or NULL.
2786
 */
2787
static xmlChar *
2788
exsltDateAddDuration (const xmlChar *xstr, const xmlChar *ystr)
2789
4.49k
{
2790
4.49k
    exsltDateDurValPtr x, y, res;
2791
4.49k
    xmlChar     *ret;
2792
2793
4.49k
    if ((xstr == NULL) || (ystr == NULL))
2794
0
        return NULL;
2795
2796
4.49k
    x = exsltDateParseDuration(xstr);
2797
4.49k
    if (x == NULL)
2798
1.07k
        return NULL;
2799
2800
3.41k
    y = exsltDateParseDuration(ystr);
2801
3.41k
    if (y == NULL) {
2802
439
        exsltDateFreeDuration(x);
2803
439
        return NULL;
2804
439
    }
2805
2806
2.98k
    res = _exsltDateAddDuration(x, y);
2807
2808
2.98k
    exsltDateFreeDuration(x);
2809
2.98k
    exsltDateFreeDuration(y);
2810
2811
2.98k
    if (res == NULL)
2812
720
        return NULL;
2813
2814
2.26k
    ret = exsltDateFormatDuration(res);
2815
2.26k
    exsltDateFreeDuration(res);
2816
2817
2.26k
    return ret;
2818
2.98k
}
2819
2820
/**
2821
 * exsltDateSumFunction:
2822
 * @ns:      a node set of duration strings
2823
 *
2824
 * The date:sum function adds a set of durations together.
2825
 * The string values of the nodes in the node set passed as an argument
2826
 * are interpreted as durations and added together as if using the
2827
 * date:add-duration function. (from exslt.org)
2828
 *
2829
 * The return value is a string in the format defined for xs:duration
2830
 * in [3.2.6 duration] of [XML Schema Part 2: Datatypes].
2831
 * The durations can usually be added by summing the numbers given for
2832
 * each of the components in the durations. However, if the durations
2833
 * are differently signed, then this sometimes results in durations
2834
 * that are impossible to express in this syntax (e.g. 'P1M' + '-P1D').
2835
 * In these cases, the function returns an empty string ('').
2836
 *
2837
 * Returns duration string or NULL.
2838
 */
2839
static void
2840
exsltDateSumFunction (xmlXPathParserContextPtr ctxt, int nargs)
2841
3.23k
{
2842
3.23k
    xmlNodeSetPtr ns;
2843
3.23k
    void *user = NULL;
2844
3.23k
    xmlChar *tmp;
2845
3.23k
    exsltDateDurValPtr x, total;
2846
3.23k
    xmlChar *ret;
2847
3.23k
    int i;
2848
2849
3.23k
    if (nargs != 1) {
2850
1
  xmlXPathSetArityError (ctxt);
2851
1
  return;
2852
1
    }
2853
2854
    /* We need to delay the freeing of value->user */
2855
3.23k
    if ((ctxt->value != NULL) && ctxt->value->boolval != 0) {
2856
1
  user = ctxt->value->user;
2857
1
  ctxt->value->boolval = 0;
2858
1
  ctxt->value->user = NULL;
2859
1
    }
2860
2861
3.23k
    ns = xmlXPathPopNodeSet (ctxt);
2862
3.23k
    if (xmlXPathCheckError (ctxt))
2863
2
  return;
2864
2865
3.23k
    if ((ns == NULL) || (ns->nodeNr == 0)) {
2866
1.41k
  xmlXPathReturnEmptyString (ctxt);
2867
1.41k
  if (ns != NULL)
2868
1.41k
      xmlXPathFreeNodeSet (ns);
2869
1.41k
  return;
2870
1.41k
    }
2871
2872
1.81k
    total = exsltDateCreateDuration ();
2873
1.81k
    if (total == NULL) {
2874
1
        xmlXPathFreeNodeSet (ns);
2875
1
        return;
2876
1
    }
2877
2878
8.70k
    for (i = 0; i < ns->nodeNr; i++) {
2879
7.72k
  int result;
2880
7.72k
  tmp = xmlXPathCastNodeToString (ns->nodeTab[i]);
2881
7.72k
  if (tmp == NULL) {
2882
3
      xmlXPathFreeNodeSet (ns);
2883
3
      exsltDateFreeDuration (total);
2884
3
      return;
2885
3
  }
2886
2887
7.71k
  x = exsltDateParseDuration (tmp);
2888
7.71k
  if (x == NULL) {
2889
547
      xmlFree (tmp);
2890
547
      exsltDateFreeDuration (total);
2891
547
      xmlXPathFreeNodeSet (ns);
2892
547
      xmlXPathReturnEmptyString (ctxt);
2893
547
      return;
2894
547
  }
2895
2896
7.17k
  result = _exsltDateAddDurCalc(total, total, x);
2897
2898
7.17k
  exsltDateFreeDuration (x);
2899
7.17k
  xmlFree (tmp);
2900
7.17k
  if (!result) {
2901
276
      exsltDateFreeDuration (total);
2902
276
      xmlXPathFreeNodeSet (ns);
2903
276
      xmlXPathReturnEmptyString (ctxt);
2904
276
      return;
2905
276
  }
2906
7.17k
    }
2907
2908
986
    ret = exsltDateFormatDuration (total);
2909
986
    exsltDateFreeDuration (total);
2910
2911
986
    xmlXPathFreeNodeSet (ns);
2912
986
    if (user != NULL)
2913
0
  xmlFreeNodeList ((xmlNodePtr) user);
2914
2915
986
    if (ret == NULL)
2916
986
  xmlXPathReturnEmptyString (ctxt);
2917
983
    else
2918
986
  xmlXPathReturnString (ctxt, ret);
2919
986
}
2920
2921
/**
2922
 * exsltDateSeconds:
2923
 * @dateTime: a date/time string
2924
 *
2925
 * Implements the EXSLT - Dates and Times seconds() function:
2926
 *    number date:seconds(string?)
2927
 * The date:seconds function returns the number of seconds specified
2928
 * by the argument string. If no argument is given, then the current
2929
 * local date/time, as returned by exsltDateCurrent() is used as the
2930
 * default argument. If the date/time string is a xs:duration, then the
2931
 * years and months must be zero (or not present). Parsing a duration
2932
 * converts the fields to seconds. If the date/time string is not a
2933
 * duration (and not null), then the legal formats are:
2934
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2935
 *  - xs:date     (CCYY-MM-DD)
2936
 *  - xs:gYearMonth (CCYY-MM)
2937
 *  - xs:gYear      (CCYY)
2938
 * In these cases the difference between the @dateTime and
2939
 * 1970-01-01T00:00:00Z is calculated and converted to seconds.
2940
 *
2941
 * Note that there was some confusion over whether "difference" meant
2942
 * that a dateTime of 1970-01-01T00:00:01Z should be a positive one or
2943
 * a negative one.  After correspondence with exslt.org, it was determined
2944
 * that the intent of the specification was to have it positive.  The
2945
 * coding was modified in July 2003 to reflect this.
2946
 *
2947
 * Returns seconds or Nan.
2948
 */
2949
static double
2950
exsltDateSeconds (const xmlChar *dateTime)
2951
11.4k
{
2952
11.4k
    exsltDateValPtr dt;
2953
11.4k
    exsltDateDurValPtr dur = NULL;
2954
11.4k
    double ret = NAN;
2955
2956
11.4k
    if (dateTime == NULL) {
2957
471
  dt = exsltDateCurrent();
2958
471
  if (dt == NULL)
2959
1
      return NAN;
2960
11.0k
    } else {
2961
11.0k
        dt = exsltDateParse(dateTime);
2962
11.0k
        if (dt == NULL)
2963
8.72k
            dur = exsltDateParseDuration(dateTime);
2964
11.0k
    }
2965
2966
11.4k
    if ((dt != NULL) && (dt->type >= XS_GYEAR)) {
2967
2.47k
        exsltDateValPtr y;
2968
2.47k
        exsltDateDurValPtr diff;
2969
2970
        /*
2971
         * compute the difference between the given (or current) date
2972
         * and epoch date
2973
         */
2974
2.47k
        y = exsltDateCreateDate(XS_DATETIME);
2975
2.47k
        if (y != NULL) {
2976
2.47k
            y->year = 1970;
2977
2.47k
            y->mon  = 1;
2978
2.47k
            y->day  = 1;
2979
2.47k
            y->tz_flag = 1;
2980
2981
2.47k
            diff = _exsltDateDifference(y, dt, 1);
2982
2.47k
            if (diff != NULL) {
2983
2.44k
                ret = (double)diff->day * SECS_PER_DAY + diff->sec;
2984
2.44k
                exsltDateFreeDuration(diff);
2985
2.44k
            }
2986
2.47k
            exsltDateFreeDate(y);
2987
2.47k
        }
2988
2989
9.01k
    } else if ((dur != NULL) && (dur->mon == 0)) {
2990
1.27k
        ret = (double)dur->day * SECS_PER_DAY + dur->sec;
2991
1.27k
    }
2992
2993
11.4k
    if (dt != NULL)
2994
2.76k
        exsltDateFreeDate(dt);
2995
11.4k
    if (dur != NULL)
2996
1.54k
        exsltDateFreeDuration(dur);
2997
2998
11.4k
    return ret;
2999
11.4k
}
3000
3001
/**
3002
 * exsltDateDifference:
3003
 * @xstr: date/time string
3004
 * @ystr: date/time string
3005
 *
3006
 * Implements the date:difference (string,string) function which returns
3007
 * the duration between the first date and the second date. If the first
3008
 * date occurs before the second date, then the result is a positive
3009
 * duration; if it occurs after the second date, the result is a
3010
 * negative duration.  The two dates must both be right-truncated
3011
 * date/time strings in one of the formats defined in [XML Schema Part
3012
 * 2: Datatypes]. The date/time with the most specific format (i.e. the
3013
 * least truncation) is converted into the same format as the date with
3014
 * the least specific format (i.e. the most truncation). The permitted
3015
 * formats are as follows, from most specific to least specific:
3016
 *  - xs:dateTime (CCYY-MM-DDThh:mm:ss)
3017
 *  - xs:date (CCYY-MM-DD)
3018
 *  - xs:gYearMonth (CCYY-MM)
3019
 *  - xs:gYear (CCYY)
3020
 * If either of the arguments is not in one of these formats,
3021
 * date:difference returns the empty string ('').
3022
 * The difference between the date/times is returned as a string in the
3023
 * format defined for xs:duration in [3.2.6 duration] of [XML Schema
3024
 * Part 2: Datatypes].
3025
 * If the date/time string with the least specific format is in either
3026
 * xs:gYearMonth or xs:gYear format, then the number of days, hours,
3027
 * minutes and seconds in the duration string must be equal to zero.
3028
 * (The format of the string will be PnYnM.) The number of months
3029
 * specified in the duration must be less than 12.
3030
 * Otherwise, the number of years and months in the duration string
3031
 * must be equal to zero. (The format of the string will be
3032
 * PnDTnHnMnS.) The number of seconds specified in the duration string
3033
 * must be less than 60; the number of minutes must be less than 60;
3034
 * the number of hours must be less than 24.
3035
 *
3036
 * Returns duration string or NULL.
3037
 */
3038
static xmlChar *
3039
exsltDateDifference (const xmlChar *xstr, const xmlChar *ystr)
3040
3.06k
{
3041
3.06k
    exsltDateValPtr x, y;
3042
3.06k
    exsltDateDurValPtr dur;
3043
3.06k
    xmlChar *ret = NULL;
3044
3045
3.06k
    if ((xstr == NULL) || (ystr == NULL))
3046
0
        return NULL;
3047
3048
3.06k
    x = exsltDateParse(xstr);
3049
3.06k
    if (x == NULL)
3050
334
        return NULL;
3051
3052
2.73k
    y = exsltDateParse(ystr);
3053
2.73k
    if (y == NULL) {
3054
1.04k
        exsltDateFreeDate(x);
3055
1.04k
        return NULL;
3056
1.04k
    }
3057
3058
1.69k
    if (((x->type < XS_GYEAR) || (x->type > XS_DATETIME)) ||
3059
1.69k
        ((y->type < XS_GYEAR) || (y->type > XS_DATETIME)))  {
3060
175
  exsltDateFreeDate(x);
3061
175
  exsltDateFreeDate(y);
3062
175
        return NULL;
3063
175
    }
3064
3065
1.51k
    dur = _exsltDateDifference(x, y, 0);
3066
3067
1.51k
    exsltDateFreeDate(x);
3068
1.51k
    exsltDateFreeDate(y);
3069
3070
1.51k
    if (dur == NULL)
3071
282
        return NULL;
3072
3073
1.23k
    ret = exsltDateFormatDuration(dur);
3074
1.23k
    exsltDateFreeDuration(dur);
3075
3076
1.23k
    return ret;
3077
1.51k
}
3078
3079
/**
3080
 * exsltDateDuration:
3081
 * @number: a xmlChar string
3082
 *
3083
 * Implements the The date:duration function returns a duration string
3084
 * representing the number of seconds specified by the argument string.
3085
 * If no argument is given, then the result of calling date:seconds
3086
 * without any arguments is used as a default argument.
3087
 * The duration is returned as a string in the format defined for
3088
 * xs:duration in [3.2.6 duration] of [XML Schema Part 2: Datatypes].
3089
 * The number of years and months in the duration string must be equal
3090
 * to zero. (The format of the string will be PnDTnHnMnS.) The number
3091
 * of seconds specified in the duration string must be less than 60;
3092
 * the number of minutes must be less than 60; the number of hours must
3093
 * be less than 24.
3094
 * If the argument is Infinity, -Infinity or NaN, then date:duration
3095
 * returns an empty string ('').
3096
 *
3097
 * Returns duration string or NULL.
3098
 */
3099
static xmlChar *
3100
exsltDateDuration (const xmlChar *number)
3101
4.11k
{
3102
4.11k
    exsltDateDurValPtr dur;
3103
4.11k
    double       secs, days;
3104
4.11k
    xmlChar     *ret;
3105
3106
4.11k
    if (number == NULL)
3107
204
        secs = exsltDateSeconds(number);
3108
3.91k
    else
3109
3.91k
        secs = xmlXPathCastStringToNumber(number);
3110
3111
4.11k
    if (xmlXPathIsNaN(secs))
3112
1.00k
        return NULL;
3113
3114
3.11k
    days = floor(secs / SECS_PER_DAY);
3115
3.11k
    if ((days <= (double)LONG_MIN) || (days >= (double)LONG_MAX))
3116
212
        return NULL;
3117
3118
2.90k
    dur = exsltDateCreateDuration();
3119
2.90k
    if (dur == NULL)
3120
2
        return NULL;
3121
3122
2.90k
    dur->day = (long)days;
3123
2.90k
    dur->sec = secs - days * SECS_PER_DAY;
3124
3125
2.90k
    ret = exsltDateFormatDuration(dur);
3126
2.90k
    exsltDateFreeDuration(dur);
3127
3128
2.90k
    return ret;
3129
2.90k
}
3130
3131
/****************************************************************
3132
 *                *
3133
 *    Wrappers for use by the XPath engine    *
3134
 *                *
3135
 ****************************************************************/
3136
3137
/**
3138
 * exsltDateDateTimeFunction:
3139
 * @ctxt: an XPath parser context
3140
 * @nargs : the number of arguments
3141
 *
3142
 * Wraps exsltDateDateTime() for use by the XPath engine.
3143
 */
3144
static void
3145
exsltDateDateTimeFunction (xmlXPathParserContextPtr ctxt, int nargs)
3146
0
{
3147
0
    xmlChar *ret;
3148
3149
0
    if (nargs != 0) {
3150
0
  xmlXPathSetArityError(ctxt);
3151
0
  return;
3152
0
    }
3153
3154
0
    ret = exsltDateDateTime();
3155
0
    if (ret == NULL)
3156
0
        xmlXPathReturnEmptyString(ctxt);
3157
0
    else
3158
0
        xmlXPathReturnString(ctxt, ret);
3159
0
}
3160
3161
/**
3162
 * exsltDateDateFunction:
3163
 * @ctxt: an XPath parser context
3164
 * @nargs : the number of arguments
3165
 *
3166
 * Wraps exsltDateDate() for use by the XPath engine.
3167
 */
3168
static void
3169
exsltDateDateFunction (xmlXPathParserContextPtr ctxt, int nargs)
3170
6.89k
{
3171
6.89k
    xmlChar *ret, *dt = NULL;
3172
3173
6.89k
    if ((nargs < 0) || (nargs > 1)) {
3174
1
  xmlXPathSetArityError(ctxt);
3175
1
  return;
3176
1
    }
3177
6.89k
    if (nargs == 1) {
3178
6.74k
  dt = xmlXPathPopString(ctxt);
3179
6.74k
  if (xmlXPathCheckError(ctxt)) {
3180
4
      xmlXPathSetTypeError(ctxt);
3181
4
      return;
3182
4
  }
3183
6.74k
    }
3184
3185
6.89k
    ret = exsltDateDate(dt);
3186
3187
6.89k
    if (ret == NULL) {
3188
5.38k
  xsltGenericDebug(xsltGenericDebugContext,
3189
5.38k
       "{http://exslt.org/dates-and-times}date: "
3190
5.38k
       "invalid date or format %s\n", dt);
3191
5.38k
  xmlXPathReturnEmptyString(ctxt);
3192
5.38k
    } else {
3193
1.50k
  xmlXPathReturnString(ctxt, ret);
3194
1.50k
    }
3195
3196
6.89k
    if (dt != NULL)
3197
6.74k
  xmlFree(dt);
3198
6.89k
}
3199
3200
/**
3201
 * exsltDateTimeFunction:
3202
 * @ctxt: an XPath parser context
3203
 * @nargs : the number of arguments
3204
 *
3205
 * Wraps exsltDateTime() for use by the XPath engine.
3206
 */
3207
static void
3208
exsltDateTimeFunction (xmlXPathParserContextPtr ctxt, int nargs)
3209
11.8k
{
3210
11.8k
    xmlChar *ret, *dt = NULL;
3211
3212
11.8k
    if ((nargs < 0) || (nargs > 1)) {
3213
1
  xmlXPathSetArityError(ctxt);
3214
1
  return;
3215
1
    }
3216
11.8k
    if (nargs == 1) {
3217
11.5k
  dt = xmlXPathPopString(ctxt);
3218
11.5k
  if (xmlXPathCheckError(ctxt)) {
3219
1
      xmlXPathSetTypeError(ctxt);
3220
1
      return;
3221
1
  }
3222
11.5k
    }
3223
3224
11.8k
    ret = exsltDateTime(dt);
3225
3226
11.8k
    if (ret == NULL) {
3227
8.18k
  xsltGenericDebug(xsltGenericDebugContext,
3228
8.18k
       "{http://exslt.org/dates-and-times}time: "
3229
8.18k
       "invalid date or format %s\n", dt);
3230
8.18k
  xmlXPathReturnEmptyString(ctxt);
3231
8.18k
    } else {
3232
3.63k
  xmlXPathReturnString(ctxt, ret);
3233
3.63k
    }
3234
3235
11.8k
    if (dt != NULL)
3236
11.5k
  xmlFree(dt);
3237
11.8k
}
3238
3239
/**
3240
 * exsltDateYearFunction:
3241
 * @ctxt: an XPath parser context
3242
 * @nargs : the number of arguments
3243
 *
3244
 * Wraps exsltDateYear() for use by the XPath engine.
3245
 */
3246
static void
3247
exsltDateYearFunction (xmlXPathParserContextPtr ctxt, int nargs)
3248
10.9k
{
3249
10.9k
    xmlChar *dt = NULL;
3250
10.9k
    double ret;
3251
3252
10.9k
    if ((nargs < 0) || (nargs > 1)) {
3253
1
  xmlXPathSetArityError(ctxt);
3254
1
  return;
3255
1
    }
3256
3257
10.9k
    if (nargs == 1) {
3258
10.7k
  dt = xmlXPathPopString(ctxt);
3259
10.7k
  if (xmlXPathCheckError(ctxt)) {
3260
7
      xmlXPathSetTypeError(ctxt);
3261
7
      return;
3262
7
  }
3263
10.7k
    }
3264
3265
10.9k
    ret = exsltDateYear(dt);
3266
3267
10.9k
    if (dt != NULL)
3268
10.7k
  xmlFree(dt);
3269
3270
10.9k
    xmlXPathReturnNumber(ctxt, ret);
3271
10.9k
}
3272
3273
/**
3274
 * exsltDateLeapYearFunction:
3275
 * @ctxt: an XPath parser context
3276
 * @nargs : the number of arguments
3277
 *
3278
 * Wraps exsltDateLeapYear() for use by the XPath engine.
3279
 */
3280
static void
3281
exsltDateLeapYearFunction (xmlXPathParserContextPtr ctxt, int nargs)
3282
8.15k
{
3283
8.15k
    xmlChar *dt = NULL;
3284
8.15k
    xmlXPathObjectPtr ret;
3285
3286
8.15k
    if ((nargs < 0) || (nargs > 1)) {
3287
1
  xmlXPathSetArityError(ctxt);
3288
1
  return;
3289
1
    }
3290
3291
8.15k
    if (nargs == 1) {
3292
8.02k
  dt = xmlXPathPopString(ctxt);
3293
8.02k
  if (xmlXPathCheckError(ctxt)) {
3294
4
      xmlXPathSetTypeError(ctxt);
3295
4
      return;
3296
4
  }
3297
8.02k
    }
3298
3299
8.15k
    ret = exsltDateLeapYear(dt);
3300
3301
8.15k
    if (dt != NULL)
3302
8.02k
  xmlFree(dt);
3303
3304
8.15k
    valuePush(ctxt, ret);
3305
8.15k
}
3306
3307
#define X_IN_Y(x, y)            \
3308
static void             \
3309
exsltDate##x##In##y##Function (xmlXPathParserContextPtr ctxt, \
3310
106k
            int nargs) {     \
3311
106k
    xmlChar *dt = NULL;           \
3312
106k
    double ret;             \
3313
106k
                \
3314
106k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
28
  xmlXPathSetArityError(ctxt);       \
3316
28
  return;             \
3317
28
    }                \
3318
106k
                \
3319
106k
    if (nargs == 1) {           \
3320
104k
  dt = xmlXPathPopString(ctxt);       \
3321
104k
  if (xmlXPathCheckError(ctxt)) {       \
3322
23
      xmlXPathSetTypeError(ctxt);       \
3323
23
      return;           \
3324
23
  }              \
3325
104k
    }                \
3326
106k
                \
3327
106k
    ret = exsltDate##x##In##y(dt);        \
3328
106k
                \
3329
106k
    if (dt != NULL)           \
3330
106k
  xmlFree(dt);           \
3331
106k
                \
3332
106k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
106k
}
date.c:exsltDateDayInMonthFunction
Line
Count
Source
3310
10.9k
            int nargs) {     \
3311
10.9k
    xmlChar *dt = NULL;           \
3312
10.9k
    double ret;             \
3313
10.9k
                \
3314
10.9k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
1
  xmlXPathSetArityError(ctxt);       \
3316
1
  return;             \
3317
1
    }                \
3318
10.9k
                \
3319
10.9k
    if (nargs == 1) {           \
3320
10.7k
  dt = xmlXPathPopString(ctxt);       \
3321
10.7k
  if (xmlXPathCheckError(ctxt)) {       \
3322
3
      xmlXPathSetTypeError(ctxt);       \
3323
3
      return;           \
3324
3
  }              \
3325
10.7k
    }                \
3326
10.9k
                \
3327
10.9k
    ret = exsltDate##x##In##y(dt);        \
3328
10.9k
                \
3329
10.9k
    if (dt != NULL)           \
3330
10.9k
  xmlFree(dt);           \
3331
10.9k
                \
3332
10.9k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
10.9k
}
date.c:exsltDateDayInWeekFunction
Line
Count
Source
3310
9.81k
            int nargs) {     \
3311
9.81k
    xmlChar *dt = NULL;           \
3312
9.81k
    double ret;             \
3313
9.81k
                \
3314
9.81k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
10
  xmlXPathSetArityError(ctxt);       \
3316
10
  return;             \
3317
10
    }                \
3318
9.81k
                \
3319
9.81k
    if (nargs == 1) {           \
3320
9.68k
  dt = xmlXPathPopString(ctxt);       \
3321
9.68k
  if (xmlXPathCheckError(ctxt)) {       \
3322
3
      xmlXPathSetTypeError(ctxt);       \
3323
3
      return;           \
3324
3
  }              \
3325
9.68k
    }                \
3326
9.80k
                \
3327
9.80k
    ret = exsltDate##x##In##y(dt);        \
3328
9.79k
                \
3329
9.79k
    if (dt != NULL)           \
3330
9.79k
  xmlFree(dt);           \
3331
9.79k
                \
3332
9.79k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
9.79k
}
date.c:exsltDateDayInYearFunction
Line
Count
Source
3310
11.5k
            int nargs) {     \
3311
11.5k
    xmlChar *dt = NULL;           \
3312
11.5k
    double ret;             \
3313
11.5k
                \
3314
11.5k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
1
  xmlXPathSetArityError(ctxt);       \
3316
1
  return;             \
3317
1
    }                \
3318
11.5k
                \
3319
11.5k
    if (nargs == 1) {           \
3320
11.2k
  dt = xmlXPathPopString(ctxt);       \
3321
11.2k
  if (xmlXPathCheckError(ctxt)) {       \
3322
3
      xmlXPathSetTypeError(ctxt);       \
3323
3
      return;           \
3324
3
  }              \
3325
11.2k
    }                \
3326
11.5k
                \
3327
11.5k
    ret = exsltDate##x##In##y(dt);        \
3328
11.5k
                \
3329
11.5k
    if (dt != NULL)           \
3330
11.5k
  xmlFree(dt);           \
3331
11.5k
                \
3332
11.5k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
11.5k
}
date.c:exsltDateDayOfWeekInMonthFunction
Line
Count
Source
3310
9.69k
            int nargs) {     \
3311
9.69k
    xmlChar *dt = NULL;           \
3312
9.69k
    double ret;             \
3313
9.69k
                \
3314
9.69k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
1
  xmlXPathSetArityError(ctxt);       \
3316
1
  return;             \
3317
1
    }                \
3318
9.69k
                \
3319
9.69k
    if (nargs == 1) {           \
3320
9.62k
  dt = xmlXPathPopString(ctxt);       \
3321
9.62k
  if (xmlXPathCheckError(ctxt)) {       \
3322
1
      xmlXPathSetTypeError(ctxt);       \
3323
1
      return;           \
3324
1
  }              \
3325
9.62k
    }                \
3326
9.69k
                \
3327
9.69k
    ret = exsltDate##x##In##y(dt);        \
3328
9.69k
                \
3329
9.69k
    if (dt != NULL)           \
3330
9.69k
  xmlFree(dt);           \
3331
9.69k
                \
3332
9.69k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
9.69k
}
date.c:exsltDateHourInDayFunction
Line
Count
Source
3310
10.3k
            int nargs) {     \
3311
10.3k
    xmlChar *dt = NULL;           \
3312
10.3k
    double ret;             \
3313
10.3k
                \
3314
10.3k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
10
  xmlXPathSetArityError(ctxt);       \
3316
10
  return;             \
3317
10
    }                \
3318
10.3k
                \
3319
10.3k
    if (nargs == 1) {           \
3320
10.1k
  dt = xmlXPathPopString(ctxt);       \
3321
10.1k
  if (xmlXPathCheckError(ctxt)) {       \
3322
2
      xmlXPathSetTypeError(ctxt);       \
3323
2
      return;           \
3324
2
  }              \
3325
10.1k
    }                \
3326
10.3k
                \
3327
10.3k
    ret = exsltDate##x##In##y(dt);        \
3328
10.3k
                \
3329
10.3k
    if (dt != NULL)           \
3330
10.3k
  xmlFree(dt);           \
3331
10.3k
                \
3332
10.3k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
10.3k
}
date.c:exsltDateMinuteInHourFunction
Line
Count
Source
3310
12.9k
            int nargs) {     \
3311
12.9k
    xmlChar *dt = NULL;           \
3312
12.9k
    double ret;             \
3313
12.9k
                \
3314
12.9k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
1
  xmlXPathSetArityError(ctxt);       \
3316
1
  return;             \
3317
1
    }                \
3318
12.9k
                \
3319
12.9k
    if (nargs == 1) {           \
3320
12.7k
  dt = xmlXPathPopString(ctxt);       \
3321
12.7k
  if (xmlXPathCheckError(ctxt)) {       \
3322
4
      xmlXPathSetTypeError(ctxt);       \
3323
4
      return;           \
3324
4
  }              \
3325
12.7k
    }                \
3326
12.9k
                \
3327
12.9k
    ret = exsltDate##x##In##y(dt);        \
3328
12.9k
                \
3329
12.9k
    if (dt != NULL)           \
3330
12.9k
  xmlFree(dt);           \
3331
12.9k
                \
3332
12.9k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
12.9k
}
date.c:exsltDateMonthInYearFunction
Line
Count
Source
3310
9.62k
            int nargs) {     \
3311
9.62k
    xmlChar *dt = NULL;           \
3312
9.62k
    double ret;             \
3313
9.62k
                \
3314
9.62k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
1
  xmlXPathSetArityError(ctxt);       \
3316
1
  return;             \
3317
1
    }                \
3318
9.62k
                \
3319
9.62k
    if (nargs == 1) {           \
3320
9.51k
  dt = xmlXPathPopString(ctxt);       \
3321
9.51k
  if (xmlXPathCheckError(ctxt)) {       \
3322
1
      xmlXPathSetTypeError(ctxt);       \
3323
1
      return;           \
3324
1
  }              \
3325
9.51k
    }                \
3326
9.62k
                \
3327
9.62k
    ret = exsltDate##x##In##y(dt);        \
3328
9.61k
                \
3329
9.61k
    if (dt != NULL)           \
3330
9.61k
  xmlFree(dt);           \
3331
9.61k
                \
3332
9.61k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
9.61k
}
date.c:exsltDateSecondInMinuteFunction
Line
Count
Source
3310
13.9k
            int nargs) {     \
3311
13.9k
    xmlChar *dt = NULL;           \
3312
13.9k
    double ret;             \
3313
13.9k
                \
3314
13.9k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
1
  xmlXPathSetArityError(ctxt);       \
3316
1
  return;             \
3317
1
    }                \
3318
13.9k
                \
3319
13.9k
    if (nargs == 1) {           \
3320
13.8k
  dt = xmlXPathPopString(ctxt);       \
3321
13.8k
  if (xmlXPathCheckError(ctxt)) {       \
3322
2
      xmlXPathSetTypeError(ctxt);       \
3323
2
      return;           \
3324
2
  }              \
3325
13.8k
    }                \
3326
13.9k
                \
3327
13.9k
    ret = exsltDate##x##In##y(dt);        \
3328
13.9k
                \
3329
13.9k
    if (dt != NULL)           \
3330
13.9k
  xmlFree(dt);           \
3331
13.9k
                \
3332
13.9k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
13.9k
}
date.c:exsltDateWeekInMonthFunction
Line
Count
Source
3310
3.01k
            int nargs) {     \
3311
3.01k
    xmlChar *dt = NULL;           \
3312
3.01k
    double ret;             \
3313
3.01k
                \
3314
3.01k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
1
  xmlXPathSetArityError(ctxt);       \
3316
1
  return;             \
3317
1
    }                \
3318
3.01k
                \
3319
3.01k
    if (nargs == 1) {           \
3320
2.95k
  dt = xmlXPathPopString(ctxt);       \
3321
2.95k
  if (xmlXPathCheckError(ctxt)) {       \
3322
1
      xmlXPathSetTypeError(ctxt);       \
3323
1
      return;           \
3324
1
  }              \
3325
2.95k
    }                \
3326
3.01k
                \
3327
3.01k
    ret = exsltDate##x##In##y(dt);        \
3328
3.01k
                \
3329
3.01k
    if (dt != NULL)           \
3330
3.01k
  xmlFree(dt);           \
3331
3.01k
                \
3332
3.01k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
3.01k
}
date.c:exsltDateWeekInYearFunction
Line
Count
Source
3310
14.6k
            int nargs) {     \
3311
14.6k
    xmlChar *dt = NULL;           \
3312
14.6k
    double ret;             \
3313
14.6k
                \
3314
14.6k
    if ((nargs < 0) || (nargs > 1)) {       \
3315
1
  xmlXPathSetArityError(ctxt);       \
3316
1
  return;             \
3317
1
    }                \
3318
14.6k
                \
3319
14.6k
    if (nargs == 1) {           \
3320
14.3k
  dt = xmlXPathPopString(ctxt);       \
3321
14.3k
  if (xmlXPathCheckError(ctxt)) {       \
3322
3
      xmlXPathSetTypeError(ctxt);       \
3323
3
      return;           \
3324
3
  }              \
3325
14.3k
    }                \
3326
14.6k
                \
3327
14.6k
    ret = exsltDate##x##In##y(dt);        \
3328
14.6k
                \
3329
14.6k
    if (dt != NULL)           \
3330
14.6k
  xmlFree(dt);           \
3331
14.6k
                \
3332
14.6k
    xmlXPathReturnNumber(ctxt, ret);        \
3333
14.6k
}
3334
3335
/**
3336
 * exsltDateMonthInYearFunction:
3337
 * @ctxt: an XPath parser context
3338
 * @nargs : the number of arguments
3339
 *
3340
 * Wraps exsltDateMonthInYear() for use by the XPath engine.
3341
 */
3342
X_IN_Y(Month,Year)
3343
3344
/**
3345
 * exsltDateMonthNameFunction:
3346
 * @ctxt: an XPath parser context
3347
 * @nargs : the number of arguments
3348
 *
3349
 * Wraps exsltDateMonthName() for use by the XPath engine.
3350
 */
3351
static void
3352
exsltDateMonthNameFunction (xmlXPathParserContextPtr ctxt, int nargs)
3353
9.17k
{
3354
9.17k
    xmlChar *dt = NULL;
3355
9.17k
    const xmlChar *ret;
3356
3357
9.17k
    if ((nargs < 0) || (nargs > 1)) {
3358
1
  xmlXPathSetArityError(ctxt);
3359
1
  return;
3360
1
    }
3361
3362
9.17k
    if (nargs == 1) {
3363
9.09k
  dt = xmlXPathPopString(ctxt);
3364
9.09k
  if (xmlXPathCheckError(ctxt)) {
3365
4
      xmlXPathSetTypeError(ctxt);
3366
4
      return;
3367
4
  }
3368
9.09k
    }
3369
3370
9.16k
    ret = exsltDateMonthName(dt);
3371
3372
9.16k
    if (dt != NULL)
3373
9.08k
  xmlFree(dt);
3374
3375
9.16k
    if (ret == NULL)
3376
9.16k
  xmlXPathReturnEmptyString(ctxt);
3377
9.16k
    else
3378
9.16k
  xmlXPathReturnString(ctxt, xmlStrdup(ret));
3379
9.16k
}
3380
3381
/**
3382
 * exsltDateMonthAbbreviationFunction:
3383
 * @ctxt: an XPath parser context
3384
 * @nargs : the number of arguments
3385
 *
3386
 * Wraps exsltDateMonthAbbreviation() for use by the XPath engine.
3387
 */
3388
static void
3389
exsltDateMonthAbbreviationFunction (xmlXPathParserContextPtr ctxt, int nargs)
3390
9.66k
{
3391
9.66k
    xmlChar *dt = NULL;
3392
9.66k
    const xmlChar *ret;
3393
3394
9.66k
    if ((nargs < 0) || (nargs > 1)) {
3395
1
  xmlXPathSetArityError(ctxt);
3396
1
  return;
3397
1
    }
3398
3399
9.66k
    if (nargs == 1) {
3400
9.51k
  dt = xmlXPathPopString(ctxt);
3401
9.51k
  if (xmlXPathCheckError(ctxt)) {
3402
2
      xmlXPathSetTypeError(ctxt);
3403
2
      return;
3404
2
  }
3405
9.51k
    }
3406
3407
9.66k
    ret = exsltDateMonthAbbreviation(dt);
3408
3409
9.66k
    if (dt != NULL)
3410
9.51k
  xmlFree(dt);
3411
3412
9.66k
    if (ret == NULL)
3413
9.66k
  xmlXPathReturnEmptyString(ctxt);
3414
9.66k
    else
3415
9.66k
  xmlXPathReturnString(ctxt, xmlStrdup(ret));
3416
9.66k
}
3417
3418
/**
3419
 * exsltDateWeekInYearFunction:
3420
 * @ctxt: an XPath parser context
3421
 * @nargs : the number of arguments
3422
 *
3423
 * Wraps exsltDateWeekInYear() for use by the XPath engine.
3424
 */
3425
X_IN_Y(Week,Year)
3426
3427
/**
3428
 * exsltDateWeekInMonthFunction:
3429
 * @ctxt: an XPath parser context
3430
 * @nargs : the number of arguments
3431
 *
3432
 * Wraps exsltDateWeekInMonthYear() for use by the XPath engine.
3433
 */
3434
X_IN_Y(Week,Month)
3435
3436
/**
3437
 * exsltDateDayInYearFunction:
3438
 * @ctxt: an XPath parser context
3439
 * @nargs : the number of arguments
3440
 *
3441
 * Wraps exsltDateDayInYear() for use by the XPath engine.
3442
 */
3443
X_IN_Y(Day,Year)
3444
3445
/**
3446
 * exsltDateDayInMonthFunction:
3447
 * @ctxt: an XPath parser context
3448
 * @nargs : the number of arguments
3449
 *
3450
 * Wraps exsltDateDayInMonth() for use by the XPath engine.
3451
 */
3452
X_IN_Y(Day,Month)
3453
3454
/**
3455
 * exsltDateDayOfWeekInMonthFunction:
3456
 * @ctxt: an XPath parser context
3457
 * @nargs : the number of arguments
3458
 *
3459
 * Wraps exsltDayOfWeekInMonth() for use by the XPath engine.
3460
 */
3461
X_IN_Y(DayOfWeek,Month)
3462
3463
/**
3464
 * exsltDateDayInWeekFunction:
3465
 * @ctxt: an XPath parser context
3466
 * @nargs : the number of arguments
3467
 *
3468
 * Wraps exsltDateDayInWeek() for use by the XPath engine.
3469
 */
3470
X_IN_Y(Day,Week)
3471
3472
/**
3473
 * exsltDateDayNameFunction:
3474
 * @ctxt: an XPath parser context
3475
 * @nargs : the number of arguments
3476
 *
3477
 * Wraps exsltDateDayName() for use by the XPath engine.
3478
 */
3479
static void
3480
exsltDateDayNameFunction (xmlXPathParserContextPtr ctxt, int nargs)
3481
7.66k
{
3482
7.66k
    xmlChar *dt = NULL;
3483
7.66k
    const xmlChar *ret;
3484
3485
7.66k
    if ((nargs < 0) || (nargs > 1)) {
3486
1
  xmlXPathSetArityError(ctxt);
3487
1
  return;
3488
1
    }
3489
3490
7.66k
    if (nargs == 1) {
3491
7.56k
  dt = xmlXPathPopString(ctxt);
3492
7.56k
  if (xmlXPathCheckError(ctxt)) {
3493
1
      xmlXPathSetTypeError(ctxt);
3494
1
      return;
3495
1
  }
3496
7.56k
    }
3497
3498
7.66k
    ret = exsltDateDayName(dt);
3499
3500
7.66k
    if (dt != NULL)
3501
7.56k
  xmlFree(dt);
3502
3503
7.66k
    if (ret == NULL)
3504
7.66k
  xmlXPathReturnEmptyString(ctxt);
3505
7.66k
    else
3506
7.66k
  xmlXPathReturnString(ctxt, xmlStrdup(ret));
3507
7.66k
}
3508
3509
/**
3510
 * exsltDateMonthDayFunction:
3511
 * @ctxt: an XPath parser context
3512
 * @nargs : the number of arguments
3513
 *
3514
 * Wraps exsltDateDayAbbreviation() for use by the XPath engine.
3515
 */
3516
static void
3517
exsltDateDayAbbreviationFunction (xmlXPathParserContextPtr ctxt, int nargs)
3518
6.83k
{
3519
6.83k
    xmlChar *dt = NULL;
3520
6.83k
    const xmlChar *ret;
3521
3522
6.83k
    if ((nargs < 0) || (nargs > 1)) {
3523
1
  xmlXPathSetArityError(ctxt);
3524
1
  return;
3525
1
    }
3526
3527
6.83k
    if (nargs == 1) {
3528
6.53k
  dt = xmlXPathPopString(ctxt);
3529
6.53k
  if (xmlXPathCheckError(ctxt)) {
3530
1
      xmlXPathSetTypeError(ctxt);
3531
1
      return;
3532
1
  }
3533
6.53k
    }
3534
3535
6.83k
    ret = exsltDateDayAbbreviation(dt);
3536
3537
6.83k
    if (dt != NULL)
3538
6.53k
  xmlFree(dt);
3539
3540
6.83k
    if (ret == NULL)
3541
6.83k
  xmlXPathReturnEmptyString(ctxt);
3542
6.83k
    else
3543
6.83k
  xmlXPathReturnString(ctxt, xmlStrdup(ret));
3544
6.83k
}
3545
3546
3547
/**
3548
 * exsltDateHourInDayFunction:
3549
 * @ctxt: an XPath parser context
3550
 * @nargs : the number of arguments
3551
 *
3552
 * Wraps exsltDateHourInDay() for use by the XPath engine.
3553
 */
3554
X_IN_Y(Hour,Day)
3555
3556
/**
3557
 * exsltDateMinuteInHourFunction:
3558
 * @ctxt: an XPath parser context
3559
 * @nargs : the number of arguments
3560
 *
3561
 * Wraps exsltDateMinuteInHour() for use by the XPath engine.
3562
 */
3563
X_IN_Y(Minute,Hour)
3564
3565
/**
3566
 * exsltDateSecondInMinuteFunction:
3567
 * @ctxt: an XPath parser context
3568
 * @nargs : the number of arguments
3569
 *
3570
 * Wraps exsltDateSecondInMinute() for use by the XPath engine.
3571
 */
3572
X_IN_Y(Second,Minute)
3573
3574
/**
3575
 * exsltDateSecondsFunction:
3576
 * @ctxt: an XPath parser context
3577
 * @nargs : the number of arguments
3578
 *
3579
 * Wraps exsltDateSeconds() for use by the XPath engine.
3580
 */
3581
static void
3582
exsltDateSecondsFunction (xmlXPathParserContextPtr ctxt, int nargs)
3583
11.2k
{
3584
11.2k
    xmlChar *str = NULL;
3585
11.2k
    double   ret;
3586
3587
11.2k
    if (nargs > 1) {
3588
1
  xmlXPathSetArityError(ctxt);
3589
1
  return;
3590
1
    }
3591
3592
11.2k
    if (nargs == 1) {
3593
11.0k
  str = xmlXPathPopString(ctxt);
3594
11.0k
  if (xmlXPathCheckError(ctxt)) {
3595
3
      xmlXPathSetTypeError(ctxt);
3596
3
      return;
3597
3
  }
3598
11.0k
    }
3599
3600
11.2k
    ret = exsltDateSeconds(str);
3601
11.2k
    if (str != NULL)
3602
11.0k
  xmlFree(str);
3603
3604
11.2k
    xmlXPathReturnNumber(ctxt, ret);
3605
11.2k
}
3606
3607
/**
3608
 * exsltDateAddFunction:
3609
 * @ctxt:  an XPath parser context
3610
 * @nargs:  the number of arguments
3611
 *
3612
 * Wraps exsltDateAdd() for use by the XPath processor.
3613
 */
3614
static void
3615
exsltDateAddFunction (xmlXPathParserContextPtr ctxt, int nargs)
3616
16.4k
{
3617
16.4k
    xmlChar *ret, *xstr, *ystr;
3618
3619
16.4k
    if (nargs != 2) {
3620
1
  xmlXPathSetArityError(ctxt);
3621
1
  return;
3622
1
    }
3623
16.4k
    ystr = xmlXPathPopString(ctxt);
3624
16.4k
    if (xmlXPathCheckError(ctxt))
3625
4
  return;
3626
3627
16.3k
    xstr = xmlXPathPopString(ctxt);
3628
16.3k
    if (xmlXPathCheckError(ctxt)) {
3629
2
        xmlFree(ystr);
3630
2
  return;
3631
2
    }
3632
3633
16.3k
    ret = exsltDateAdd(xstr, ystr);
3634
3635
16.3k
    xmlFree(ystr);
3636
16.3k
    xmlFree(xstr);
3637
3638
16.3k
    if (ret == NULL)
3639
16.3k
        xmlXPathReturnEmptyString(ctxt);
3640
7.78k
    else
3641
16.3k
  xmlXPathReturnString(ctxt, ret);
3642
16.3k
}
3643
3644
/**
3645
 * exsltDateAddDurationFunction:
3646
 * @ctxt:  an XPath parser context
3647
 * @nargs:  the number of arguments
3648
 *
3649
 * Wraps exsltDateAddDuration() for use by the XPath processor.
3650
 */
3651
static void
3652
exsltDateAddDurationFunction (xmlXPathParserContextPtr ctxt, int nargs)
3653
4.49k
{
3654
4.49k
    xmlChar *ret, *xstr, *ystr;
3655
3656
4.49k
    if (nargs != 2) {
3657
2
  xmlXPathSetArityError(ctxt);
3658
2
  return;
3659
2
    }
3660
4.49k
    ystr = xmlXPathPopString(ctxt);
3661
4.49k
    if (xmlXPathCheckError(ctxt))
3662
1
  return;
3663
3664
4.49k
    xstr = xmlXPathPopString(ctxt);
3665
4.49k
    if (xmlXPathCheckError(ctxt)) {
3666
2
        xmlFree(ystr);
3667
2
  return;
3668
2
    }
3669
3670
4.49k
    ret = exsltDateAddDuration(xstr, ystr);
3671
3672
4.49k
    xmlFree(ystr);
3673
4.49k
    xmlFree(xstr);
3674
3675
4.49k
    if (ret == NULL)
3676
4.49k
        xmlXPathReturnEmptyString(ctxt);
3677
2.26k
    else
3678
4.49k
  xmlXPathReturnString(ctxt, ret);
3679
4.49k
}
3680
3681
/**
3682
 * exsltDateDifferenceFunction:
3683
 * @ctxt:  an XPath parser context
3684
 * @nargs:  the number of arguments
3685
 *
3686
 * Wraps exsltDateDifference() for use by the XPath processor.
3687
 */
3688
static void
3689
exsltDateDifferenceFunction (xmlXPathParserContextPtr ctxt, int nargs)
3690
3.07k
{
3691
3.07k
    xmlChar *ret, *xstr, *ystr;
3692
3693
3.07k
    if (nargs != 2) {
3694
1
  xmlXPathSetArityError(ctxt);
3695
1
  return;
3696
1
    }
3697
3.07k
    ystr = xmlXPathPopString(ctxt);
3698
3.07k
    if (xmlXPathCheckError(ctxt))
3699
2
  return;
3700
3701
3.06k
    xstr = xmlXPathPopString(ctxt);
3702
3.06k
    if (xmlXPathCheckError(ctxt)) {
3703
2
        xmlFree(ystr);
3704
2
  return;
3705
2
    }
3706
3707
3.06k
    ret = exsltDateDifference(xstr, ystr);
3708
3709
3.06k
    xmlFree(ystr);
3710
3.06k
    xmlFree(xstr);
3711
3712
3.06k
    if (ret == NULL)
3713
3.06k
        xmlXPathReturnEmptyString(ctxt);
3714
1.23k
    else
3715
3.06k
  xmlXPathReturnString(ctxt, ret);
3716
3.06k
}
3717
3718
/**
3719
 * exsltDateDurationFunction:
3720
 * @ctxt: an XPath parser context
3721
 * @nargs : the number of arguments
3722
 *
3723
 * Wraps exsltDateDuration() for use by the XPath engine
3724
 */
3725
static void
3726
exsltDateDurationFunction (xmlXPathParserContextPtr ctxt, int nargs)
3727
4.12k
{
3728
4.12k
    xmlChar *ret;
3729
4.12k
    xmlChar *number = NULL;
3730
3731
4.12k
    if ((nargs < 0) || (nargs > 1)) {
3732
1
  xmlXPathSetArityError(ctxt);
3733
1
  return;
3734
1
    }
3735
3736
4.12k
    if (nargs == 1) {
3737
3.91k
  number = xmlXPathPopString(ctxt);
3738
3.91k
  if (xmlXPathCheckError(ctxt)) {
3739
2
      xmlXPathSetTypeError(ctxt);
3740
2
      return;
3741
2
  }
3742
3.91k
    }
3743
3744
4.11k
    ret = exsltDateDuration(number);
3745
3746
4.11k
    if (number != NULL)
3747
3.91k
  xmlFree(number);
3748
3749
4.11k
    if (ret == NULL)
3750
4.11k
  xmlXPathReturnEmptyString(ctxt);
3751
2.90k
    else
3752
4.11k
  xmlXPathReturnString(ctxt, ret);
3753
4.11k
}
3754
3755
/**
3756
 * exsltDateRegister:
3757
 *
3758
 * Registers the EXSLT - Dates and Times module
3759
 */
3760
void
3761
exsltDateRegister (void)
3762
2
{
3763
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "add",
3764
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3765
2
           exsltDateAddFunction);
3766
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "add-duration",
3767
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3768
2
           exsltDateAddDurationFunction);
3769
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "date",
3770
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3771
2
           exsltDateDateFunction);
3772
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "date-time",
3773
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3774
2
           exsltDateDateTimeFunction);
3775
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "day-abbreviation",
3776
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3777
2
           exsltDateDayAbbreviationFunction);
3778
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-month",
3779
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3780
2
           exsltDateDayInMonthFunction);
3781
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-week",
3782
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3783
2
           exsltDateDayInWeekFunction);
3784
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-year",
3785
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3786
2
           exsltDateDayInYearFunction);
3787
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "day-name",
3788
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3789
2
           exsltDateDayNameFunction);
3790
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "day-of-week-in-month",
3791
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3792
2
           exsltDateDayOfWeekInMonthFunction);
3793
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "difference",
3794
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3795
2
           exsltDateDifferenceFunction);
3796
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "duration",
3797
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3798
2
           exsltDateDurationFunction);
3799
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "hour-in-day",
3800
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3801
2
           exsltDateHourInDayFunction);
3802
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "leap-year",
3803
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3804
2
           exsltDateLeapYearFunction);
3805
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "minute-in-hour",
3806
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3807
2
           exsltDateMinuteInHourFunction);
3808
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "month-abbreviation",
3809
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3810
2
           exsltDateMonthAbbreviationFunction);
3811
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "month-in-year",
3812
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3813
2
           exsltDateMonthInYearFunction);
3814
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "month-name",
3815
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3816
2
           exsltDateMonthNameFunction);
3817
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "second-in-minute",
3818
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3819
2
           exsltDateSecondInMinuteFunction);
3820
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "seconds",
3821
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3822
2
           exsltDateSecondsFunction);
3823
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "sum",
3824
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3825
2
           exsltDateSumFunction);
3826
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "time",
3827
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3828
2
           exsltDateTimeFunction);
3829
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "week-in-month",
3830
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3831
2
           exsltDateWeekInMonthFunction);
3832
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "week-in-year",
3833
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3834
2
           exsltDateWeekInYearFunction);
3835
2
    xsltRegisterExtModuleFunction ((const xmlChar *) "year",
3836
2
           (const xmlChar *) EXSLT_DATE_NAMESPACE,
3837
2
           exsltDateYearFunction);
3838
2
}
3839
3840
/**
3841
 * exsltDateXpathCtxtRegister:
3842
 *
3843
 * Registers the EXSLT - Dates and Times module for use outside XSLT
3844
 */
3845
int
3846
exsltDateXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix)
3847
0
{
3848
0
    if (ctxt
3849
0
        && prefix
3850
0
        && !xmlXPathRegisterNs(ctxt,
3851
0
                               prefix,
3852
0
                               (const xmlChar *) EXSLT_DATE_NAMESPACE)
3853
0
        && !xmlXPathRegisterFuncNS(ctxt,
3854
0
                                   (const xmlChar *) "add",
3855
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3856
0
                                   exsltDateAddFunction)
3857
0
        && !xmlXPathRegisterFuncNS(ctxt,
3858
0
                                   (const xmlChar *) "add-duration",
3859
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3860
0
                                   exsltDateAddDurationFunction)
3861
0
        && !xmlXPathRegisterFuncNS(ctxt,
3862
0
                                   (const xmlChar *) "date",
3863
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3864
0
                                   exsltDateDateFunction)
3865
0
        && !xmlXPathRegisterFuncNS(ctxt,
3866
0
                                   (const xmlChar *) "date-time",
3867
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3868
0
                                   exsltDateDateTimeFunction)
3869
0
        && !xmlXPathRegisterFuncNS(ctxt,
3870
0
                                   (const xmlChar *) "day-abbreviation",
3871
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3872
0
                                   exsltDateDayAbbreviationFunction)
3873
0
        && !xmlXPathRegisterFuncNS(ctxt,
3874
0
                                   (const xmlChar *) "day-in-month",
3875
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3876
0
                                   exsltDateDayInMonthFunction)
3877
0
        && !xmlXPathRegisterFuncNS(ctxt,
3878
0
                                   (const xmlChar *) "day-in-week",
3879
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3880
0
                                   exsltDateDayInWeekFunction)
3881
0
        && !xmlXPathRegisterFuncNS(ctxt,
3882
0
                                   (const xmlChar *) "day-in-year",
3883
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3884
0
                                   exsltDateDayInYearFunction)
3885
0
        && !xmlXPathRegisterFuncNS(ctxt,
3886
0
                                   (const xmlChar *) "day-name",
3887
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3888
0
                                   exsltDateDayNameFunction)
3889
0
        && !xmlXPathRegisterFuncNS(ctxt,
3890
0
                                   (const xmlChar *) "day-of-week-in-month",
3891
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3892
0
                                   exsltDateDayOfWeekInMonthFunction)
3893
0
        && !xmlXPathRegisterFuncNS(ctxt,
3894
0
                                   (const xmlChar *) "difference",
3895
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3896
0
                                   exsltDateDifferenceFunction)
3897
0
        && !xmlXPathRegisterFuncNS(ctxt,
3898
0
                                   (const xmlChar *) "duration",
3899
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3900
0
                                   exsltDateDurationFunction)
3901
0
        && !xmlXPathRegisterFuncNS(ctxt,
3902
0
                                   (const xmlChar *) "hour-in-day",
3903
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3904
0
                                   exsltDateHourInDayFunction)
3905
0
        && !xmlXPathRegisterFuncNS(ctxt,
3906
0
                                   (const xmlChar *) "leap-year",
3907
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3908
0
                                   exsltDateLeapYearFunction)
3909
0
        && !xmlXPathRegisterFuncNS(ctxt,
3910
0
                                   (const xmlChar *) "minute-in-hour",
3911
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3912
0
                                   exsltDateMinuteInHourFunction)
3913
0
        && !xmlXPathRegisterFuncNS(ctxt,
3914
0
                                   (const xmlChar *) "month-abbreviation",
3915
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3916
0
                                   exsltDateMonthAbbreviationFunction)
3917
0
        && !xmlXPathRegisterFuncNS(ctxt,
3918
0
                                   (const xmlChar *) "month-in-year",
3919
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3920
0
                                   exsltDateMonthInYearFunction)
3921
0
        && !xmlXPathRegisterFuncNS(ctxt,
3922
0
                                   (const xmlChar *) "month-name",
3923
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3924
0
                                   exsltDateMonthNameFunction)
3925
0
        && !xmlXPathRegisterFuncNS(ctxt,
3926
0
                                   (const xmlChar *) "second-in-minute",
3927
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3928
0
                                   exsltDateSecondInMinuteFunction)
3929
0
        && !xmlXPathRegisterFuncNS(ctxt,
3930
0
                                   (const xmlChar *) "seconds",
3931
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3932
0
                                   exsltDateSecondsFunction)
3933
0
        && !xmlXPathRegisterFuncNS(ctxt,
3934
0
                                   (const xmlChar *) "sum",
3935
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3936
0
                                   exsltDateSumFunction)
3937
0
        && !xmlXPathRegisterFuncNS(ctxt,
3938
0
                                   (const xmlChar *) "time",
3939
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3940
0
                                   exsltDateTimeFunction)
3941
0
        && !xmlXPathRegisterFuncNS(ctxt,
3942
0
                                   (const xmlChar *) "week-in-month",
3943
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3944
0
                                   exsltDateWeekInMonthFunction)
3945
0
        && !xmlXPathRegisterFuncNS(ctxt,
3946
0
                                   (const xmlChar *) "week-in-year",
3947
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3948
0
                                   exsltDateWeekInYearFunction)
3949
0
        && !xmlXPathRegisterFuncNS(ctxt,
3950
0
                                   (const xmlChar *) "year",
3951
0
                                   (const xmlChar *) EXSLT_DATE_NAMESPACE,
3952
0
                                   exsltDateYearFunction)) {
3953
0
        return 0;
3954
0
    }
3955
0
    return -1;
3956
0
}