}
/**
- * _exsltDateAddDuration:
- * @x: an #exsltDateValPtr of type #XS_DURATION
- * @y: an #exsltDateValPtr of type #XS_DURATION
+ * _exsltDateAddDurCalc
+ * @ret: an exsltDateValPtr for the return value:
+ * @x: an exsltDateValPtr for the first operand
+ * @y: an exsltDateValPtr for the second operand
*
- * Compute a new duration from @x and @y.
+ * Add two durations, catering for possible negative values.
+ * The sum is placed in @ret.
*
- * Returns date/time pointer or NULL.
+ * Returns 1 for success, 0 if error detected.
*/
-static exsltDateValPtr
-_exsltDateAddDuration (exsltDateValPtr x, exsltDateValPtr y)
+static int
+_exsltDateAddDurCalc (exsltDateValPtr ret, exsltDateValPtr x,
+ exsltDateValPtr y)
{
- exsltDateValPtr ret;
long carry;
- if ((x == NULL) || (y == NULL))
- return NULL;
-
- ret = exsltDateCreateDate(XS_DURATION);
- if (ret == NULL)
- return NULL;
-
/* months */
ret->value.dur.mon = x->value.dur.mon + y->value.dur.mon;
carry = (long)FQUOTIENT(ret->value.dur.sec, SECS_PER_DAY);
if (ret->value.dur.sec != 0.0) {
ret->value.dur.sec = MODULO(ret->value.dur.sec, SECS_PER_DAY);
+ /*
+ * Our function MODULO always gives us a positive value, so
+ * if we end up with a "-ve" carry we need to adjust it
+ * appropriately (bug 154021)
+ */
+ if ((carry < 0) && (ret->value.dur.sec != 0)) {
+ /* change seconds to equiv negative modulus */
+ ret->value.dur.sec = ret->value.dur.sec - SECS_PER_DAY;
+ carry++;
+ }
}
/* days */
(ret->value.dur.mon < 0)) ||
(((ret->value.dur.day < 0) || (ret->value.dur.sec < 0)) &&
(ret->value.dur.mon > 0))) {
- exsltDateFreeDate(ret);
- return NULL;
+ return 0;
}
+ return 1;
+}
- return ret;
+/**
+ * _exsltDateAddDuration:
+ * @x: an #exsltDateValPtr of type #XS_DURATION
+ * @y: an #exsltDateValPtr of type #XS_DURATION
+ *
+ * Compute a new duration from @x and @y.
+ *
+ * Returns date/time pointer or NULL.
+ */
+static exsltDateValPtr
+_exsltDateAddDuration (exsltDateValPtr x, exsltDateValPtr y)
+{
+ exsltDateValPtr ret;
+
+ if ((x == NULL) || (y == NULL))
+ return NULL;
+
+ ret = exsltDateCreateDate(XS_DURATION);
+ if (ret == NULL)
+ return NULL;
+
+ if (_exsltDateAddDurCalc(ret, x, y))
+ return ret;
+
+ exsltDateFreeDate(ret);
+ return NULL;
}
/****************************************************************
xmlChar *tmp;
exsltDateValPtr x, total;
xmlChar *ret;
- long carry;
int i;
if (nargs != 1) {
}
for (i = 0; i < ns->nodeNr; i++) {
-
+ int result;
tmp = xmlXPathCastNodeToString (ns->nodeTab[i]);
if (tmp == NULL) {
xmlXPathFreeNodeSet (ns);
return;
}
- /* months */
- total->value.dur.mon += x->value.dur.mon;
-
- /* seconds */
- total->value.dur.sec += x->value.dur.sec;
- carry = (long) FQUOTIENT (total->value.dur.sec, SECS_PER_DAY);
- if (total->value.dur.sec != 0.0) {
- total->value.dur.sec =
- MODULO (total->value.dur.sec, SECS_PER_DAY);
- }
-
- /* days */
- total->value.dur.day += x->value.dur.day + carry;
+ result = _exsltDateAddDurCalc(total, total, x);
exsltDateFreeDate (x);
xmlFree (tmp);
+ if (!result) {
+ exsltDateFreeDate (total);
+ xmlXPathFreeNodeSet (ns);
+ xmlXPathReturnEmptyString (ctxt);
+ return;
+ }
}
ret = exsltDateFormatDuration (&(total->value.dur));