Coverage Report

Created: 2023-03-26 06:14

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