Skip to content
Snippets Groups Projects
Commit 1d09e1fb781f authored by Daniel Veillard's avatar Daniel Veillard
Browse files

- functions.[ch]: Bjorn Reese <breese@mail1.stofanet.dk> provided

  number formatting !!!
- acconfig.h config.h.in configure.in libxslt/Makefile.am
  tests/Makefile.am; added testing for mathematical functions,
  fixed make test(s)
- FEATURES: updated
Daniel
parent 451d45f339fe
No related branches found
No related tags found
No related merge requests found
Thu Jan 25 12:13:04 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* functions.[ch]: Bjorn Reese <breese@mail1.stofanet.dk> provided
number formatting !!!
* acconfig.h config.h.in configure.in libxslt/Makefile.am
tests/Makefile.am; added testing for mathematical functions,
fixed make test(s)
* FEATURES: updated
Wed Jan 24 16:59:05 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr> Wed Jan 24 16:59:05 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* libxslt/xsltInternals.h libxslt/pattern.c: fixed problems * libxslt/xsltInternals.h libxslt/pattern.c: fixed problems
......
...@@ -203,7 +203,7 @@ ...@@ -203,7 +203,7 @@
NO node-set document(object, node-set?) NO node-set document(object, node-set?)
NO node-set key(string, object) NO node-set key(string, object)
NO string format-number(number, string, string?) YES string format-number(number, string, string?)
NO node-set current() NO node-set current()
NO string unparsed-entity-uri(string) NO string unparsed-entity-uri(string)
NO string generate-id(node-set?) NO string generate-id(node-set?)
......
#undef HAVE_ISINF
#undef HAVE_ISNAN
#undef HAVE_POW
#undef HAVE_FLOOR
#undef HAVE_FABS
...@@ -5,3 +5,24 @@ ...@@ -5,3 +5,24 @@
/* Define if you have the ANSI C header files. */ /* Define if you have the ANSI C header files. */
#undef STDC_HEADERS #undef STDC_HEADERS
#undef HAVE_ISINF
#undef HAVE_ISNAN
#undef HAVE_POW
#undef HAVE_FLOOR
#undef HAVE_FABS
/* Define if you have the <float.h> header file. */
#undef HAVE_FLOAT_H
/* Define if you have the <fp_class.h> header file. */
#undef HAVE_FP_CLASS_H
/* Define if you have the <ieeefp.h> header file. */
#undef HAVE_IEEEFP_H
/* Define if you have the <math.h> header file. */
#undef HAVE_MATH_H
/* Define if you have the <nan.h> header file. */
#undef HAVE_NAN_H
...@@ -8,6 +8,37 @@ ...@@ -8,6 +8,37 @@
AM_MAINTAINER_MODE AM_MAINTAINER_MODE
dnl dnl
dnl Check the environment
dnl
AC_ISC_POSIX
AC_PROG_CC
AC_STDC_HEADERS
AC_ARG_PROGRAM
AM_PROG_LIBTOOL
dnl
dnl Math detection
dnl
AC_CHECK_HEADERS(ieeefp.h nan.h math.h fp_class.h float.h)
AC_CHECK_FUNC(isnan, , AC_CHECK_LIB(m, isnan,
[M_LIBS="-lm"; AC_DEFINE(HAVE_ISNAN)]))
AC_CHECK_FUNC(isinf, , AC_CHECK_LIB(m, isinf,
[M_LIBS="-lm"; AC_DEFINE(HAVE_ISINF)]))
AC_CHECK_FUNC(pow, , AC_CHECK_LIB(m, pow,
[M_LIBS="-lm"; AC_DEFINE(HAVE_POW)]))
AC_CHECK_FUNC(floor, , AC_CHECK_LIB(m, pow,
[M_LIBS="-lm"; AC_DEFINE(HAVE_FLOOR)]))
AC_CHECK_FUNC(fabs, , AC_CHECK_LIB(m, pow,
[M_LIBS="-lm"; AC_DEFINE(HAVE_FABS)]))
dnl
dnl Debug for DV dnl Debug for DV
dnl dnl
if test "${LOGNAME}" = "veillard" -a "`pwd`" = "/u/veillard/XSLT" ; then if test "${LOGNAME}" = "veillard" -a "`pwd`" = "/u/veillard/XSLT" ; then
...@@ -49,16 +80,6 @@ ...@@ -49,16 +80,6 @@
) )
dnl
dnl Check the environment
dnl
AC_ISC_POSIX
AC_PROG_CC
AC_STDC_HEADERS
AC_ARG_PROGRAM
AM_PROG_LIBTOOL
dnl No internationalization (yet ?) dnl No internationalization (yet ?)
dnl dnl
dnl ALL_LINGUAS="it ko fr de es no ga sv pt ja fi cs" dnl ALL_LINGUAS="it ko fr de es no ga sv pt ja fi cs"
...@@ -110,7 +131,8 @@ ...@@ -110,7 +131,8 @@
XSLT_LIBDIR='-L${libdir}' XSLT_LIBDIR='-L${libdir}'
XSLT_INCLUDEDIR='-I${includedir}' XSLT_INCLUDEDIR='-I${includedir}'
XSLT_LIBS="-lxslt $LIBXML_LIBS" EXTRA_LIBS="$LIBXML_LIBS $M_LIBS"
XSLT_LIBS="-lxslt $LIBXML_LIBS $M_LIBS"
AC_SUBST(XSLT_LIBDIR) AC_SUBST(XSLT_LIBDIR)
AC_SUBST(XSLT_INCLUDEDIR) AC_SUBST(XSLT_INCLUDEDIR)
...@@ -114,6 +136,7 @@ ...@@ -114,6 +136,7 @@
AC_SUBST(XSLT_LIBDIR) AC_SUBST(XSLT_LIBDIR)
AC_SUBST(XSLT_INCLUDEDIR) AC_SUBST(XSLT_INCLUDEDIR)
AC_SUBST(EXTRA_LIBS)
AC_SUBST(XSLT_LIBS) AC_SUBST(XSLT_LIBS)
AC_OUTPUT([ AC_OUTPUT([
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
bin_PROGRAMS = xsltproc bin_PROGRAMS = xsltproc
DEPS = $(top_builddir)/libxslt/libxslt.la DEPS = $(top_builddir)/libxslt/libxslt.la
LDADDS = -L. $(top_builddir)/libxslt/libxslt.la $(LIBXML_LIBS) LDADDS = -L. $(top_builddir)/libxslt/libxslt.la $(EXTRA_LIBS)
xsltproc_SOURCES = xsltproc.c xsltproc_SOURCES = xsltproc.c
xsltproc_LDFLAGS = xsltproc_LDFLAGS =
......
...@@ -7,9 +7,10 @@ ...@@ -7,9 +7,10 @@
* See Copyright for the status of this software. * See Copyright for the status of this software.
* *
* Daniel.Veillard@imag.fr * Daniel.Veillard@imag.fr
* Bjorn Reese <breese@mail1.stofanet.dk> for number formatting
*/ */
#include "xsltconfig.h" #include "xsltconfig.h"
#include <string.h> #include <string.h>
...@@ -10,7 +11,26 @@ ...@@ -10,7 +11,26 @@
*/ */
#include "xsltconfig.h" #include "xsltconfig.h"
#include <string.h> #include <string.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#endif
#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif
#ifdef HAVE_NAN_H
#include <nan.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include <libxml/xmlmemory.h> #include <libxml/xmlmemory.h>
...@@ -16,4 +36,5 @@ ...@@ -16,4 +36,5 @@
#include <libxml/xmlmemory.h> #include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <libxml/tree.h> #include <libxml/tree.h>
#include <libxml/valid.h> #include <libxml/valid.h>
#include <libxml/hash.h> #include <libxml/hash.h>
...@@ -28,6 +49,50 @@ ...@@ -28,6 +49,50 @@
#define DEBUG_FUNCTION #define DEBUG_FUNCTION
#ifndef FALSE
# define FALSE (0 == 1)
# define TRUE (1 == 1)
#endif
#define DIGIT_LIST "0123456789"
#define SYMBOL_QUOTE ((xmlChar)'\'')
#define SYMBOL_PATTERN_SEPARATOR ((xmlChar)';')
#define SYMBOL_ZERO_DIGIT ((xmlChar)'#')
#define SYMBOL_DIGIT ((xmlChar)'0')
#define SYMBOL_DECIMAL_POINT ((xmlChar)'.')
#define SYMBOL_GROUPING ((xmlChar)',')
#define SYMBOL_MINUS ((xmlChar)'-')
#define SYMBOL_PERCENT ((xmlChar)'%')
#define SYMBOL_PERMILLE ((xmlChar)'?')
static struct _xsltDecimalFormat globalDecimalFormat;
/************************************************************************
* *
* Utility functions *
* *
************************************************************************/
#ifndef isnan
static int
isnan(volatile double number)
{
return (!(number < 0.0 || number > 0.0) && (number != 0.0));
}
#endif
#ifndef isinf
static int
isinf(double number)
{
# ifdef HUGE_VAL
return ((number == HUGE_VAL) ? 1 : ((number == -HUGE_VAL) ? -1 : 0));
# else
return FALSE;
# endif
}
#endif
/************************************************************************ /************************************************************************
* * * *
...@@ -82,4 +147,212 @@ ...@@ -82,4 +147,212 @@
* Implement the format-number() XSLT function * Implement the format-number() XSLT function
* string format-number(number, string, string?) * string format-number(number, string, string?)
*/ */
/*
* JDK 1.1 DecimalFormat class:
*
* http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html
*
* Structure:
*
* pattern := subpattern{;subpattern}
* subpattern := {prefix}integer{.fraction}{suffix}
* prefix := '\\u0000'..'\\uFFFD' - specialCharacters
* suffix := '\\u0000'..'\\uFFFD' - specialCharacters
* integer := '#'* '0'* '0'
* fraction := '0'* '#'*
*
* Notation:
* X* 0 or more instances of X
* (X | Y) either X or Y.
* X..Y any character from X up to Y, inclusive.
* S - T characters in S, except those in T
*
* Special Characters:
*
* Symbol Meaning
* 0 a digit
* # a digit, zero shows as absent
* . placeholder for decimal separator
* , placeholder for grouping separator.
* ; separates formats.
* - default negative prefix.
* % multiply by 100 and show as percentage
* ? multiply by 1000 and show as per mille
* X any other characters can be used in the prefix or suffix
* ' used to quote special characters in a prefix or suffix.
*/
/* TODO
*
* The JDK description does not tell where percent and permille may
* and may not appear within the format string.
*
* Error handling.
*
* Inf and NaN not tested.
*/
#define IS_SPECIAL(self,letter) \
((letter == self->zeroDigit) || \
(letter == self->digit) || \
(letter == self->decimalPoint) || \
(letter == self->grouping) || \
(letter == self->minusSign) || \
(letter == self->percent) || \
(letter == self->permille)) \
static xmlChar *
PrivateDecimalFormat(xsltDecimalFormatPtr self,
xmlChar *format,
double number)
{
xmlChar *the_format;
xmlBufferPtr buffer;
xmlChar *result;
char digit_buffer[2];
int use_minus;
int i, j;
int length;
int group;
int integer_digits = 0;
int integer_zeroes = 0;
int fraction_digits = 0;
int fraction_zeroes = 0;
int decimal_point;
double divisor;
int digit;
buffer = xmlBufferCreate();
/* Find positive or negative template */
the_format = (xmlChar *)xmlStrchr(format,
self->patternSeparator);
if ((the_format != NULL) && (number < 0.0)) {
/* Use negative template */
the_format++;
use_minus = FALSE;
} else {
/* Use positive template */
if (the_format)
the_format[0] = 0;
the_format = format;
use_minus = (number < 0.0) ? TRUE : FALSE;
}
/* Prefix */
length = xmlStrlen(the_format);
for (i = 0; i < length; i++) {
if (IS_SPECIAL(self, the_format[i])) {
break; /* for */
} else {
if (the_format[i] == SYMBOL_QUOTE) {
/* Quote character */
i++;
}
xmlBufferAdd(buffer, &the_format[i], 1);
}
}
if (isinf(number)) {
xmlBufferCat(buffer, self->infinity);
/* Skip until suffix */
for ( ; i < length; i++) {
if (! IS_SPECIAL(self, the_format[i]))
break; /* for */
}
} else if (isnan(number)) {
xmlBufferCat(buffer, self->noNumber);
/* Skip until suffix */
for ( ; i < length; i++) {
if (! IS_SPECIAL(self, the_format[i]))
break; /* for */
}
} else {
/* Parse the number part of the format string */
decimal_point = FALSE;
group = 0;
for ( ; i < length; i++) {
if (the_format[i] == self->digit) {
if (decimal_point) {
if (fraction_zeroes > 0)
; /* Error in format */
fraction_digits++;
} else {
integer_digits++;
group++;
}
} else if (the_format[i] == self->zeroDigit) {
if (decimal_point)
fraction_zeroes++;
else {
if (integer_digits > 0)
; /* Error in format */
integer_zeroes++;
group++;
}
} else if (the_format[i] == self->grouping) {
if (decimal_point)
; /* Error in format */
group = 0;
} else if (the_format[i] == self->decimalPoint) {
if (decimal_point)
; /* Error in format */
decimal_point = TRUE;
} else
break;
}
/* Format the number */
if (use_minus)
xmlBufferAdd(buffer, &(self->minusSign), 1);
number = fabs(number);
number = floor(0.5 + number * pow(10.0, (double)(fraction_digits + fraction_zeroes)));
/* Integer part */
digit_buffer[1] = (char)0;
j = integer_digits + integer_zeroes;
divisor = pow(10.0, (double)(integer_digits + integer_zeroes + fraction_digits + fraction_zeroes - 1));
for ( ; j > 0; j--) {
digit = (int)(number / divisor);
number -= (double)digit * divisor;
divisor /= 10.0;
if ((digit > 0) || (j <= integer_digits)) {
digit_buffer[0] = DIGIT_LIST[digit];
xmlBufferCCat(buffer, digit_buffer);
}
}
if (decimal_point)
xmlBufferAdd(buffer, &(self->decimalPoint), 1);
/* Fraction part */
for (j = fraction_digits + fraction_zeroes; j > 0; j--) {
digit = (int)(number / divisor);
number -= (double)digit * divisor;
divisor /= 10.0;
if ((digit > 0) || (j > fraction_zeroes)) {
digit_buffer[0] = DIGIT_LIST[digit];
xmlBufferCCat(buffer, digit_buffer);
}
}
}
/* Suffix */
for ( ; i < length; i++) {
if (the_format[i] == SYMBOL_QUOTE)
i++;
xmlBufferAdd(buffer, &the_format[i], 1);
}
result = xmlStrdup(xmlBufferContent(buffer));
xmlBufferFree(buffer);
return result;
}
void void
...@@ -85,6 +358,34 @@ ...@@ -85,6 +358,34 @@
void void
xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs){ xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs)
TODO /* function */ {
xmlXPathObjectPtr numberObj = NULL;
xmlXPathObjectPtr formatObj = NULL;
xmlXPathObjectPtr decimalObj = NULL;
switch (nargs) {
case 3:
CAST_TO_STRING;
decimalObj = valuePop(ctxt);
globalDecimalFormat.decimalPoint = decimalObj->stringval[0]; /* hack */
/* Intentional fall-through */
case 2:
CAST_TO_STRING;
formatObj = valuePop(ctxt);
CAST_TO_NUMBER;
numberObj = valuePop(ctxt);
break;
default:
XP_ERROR(XPATH_INVALID_ARITY);
}
valuePush(ctxt,
xmlXPathNewString(PrivateDecimalFormat(&globalDecimalFormat,
formatObj->stringval,
numberObj->floatval)));
xmlXPathFreeObject(numberObj);
xmlXPathFreeObject(formatObj);
xmlXPathFreeObject(decimalObj);
} }
/** /**
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* See Copyright for the status of this software. * See Copyright for the status of this software.
* *
* Daniel.Veillard@imag.fr * Daniel.Veillard@imag.fr
* Bjorn Reese <breese@mail1.stofanet.dk> for number formatting
*/ */
#ifndef __XML_XSLT_FUNCTIONS_H__ #ifndef __XML_XSLT_FUNCTIONS_H__
...@@ -18,6 +19,25 @@ ...@@ -18,6 +19,25 @@
#endif #endif
/* /*
* Data structure of decimal-format
*/
typedef struct _xsltDecimalFormat {
/* Used for interpretation of pattern */
xmlChar digit;
xmlChar patternSeparator;
/* May appear in result */
xmlChar minusSign;
xmlChar *infinity;
xmlChar *noNumber;
/* Used for interpretation of pattern and may appear in result */
xmlChar decimalPoint;
xmlChar grouping;
xmlChar percent;
xmlChar permille;
xmlChar zeroDigit;
} xsltDecimalFormat, *xsltDecimalFormatPtr;
/*
* Interfaces for the functions implementations * Interfaces for the functions implementations
*/ */
......
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
SUBDIRS=REC1 REC2 SUBDIRS=REC1 REC2
test tests: all
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment