From: Daniel Veillard Date: Thu, 25 Jan 2001 11:16:26 +0000 (+0000) Subject: - functions.[ch]: Bjorn Reese provided X-Git-Tag: v1.1.28~1513 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a7da804741d2650c5132ab004d442d7dc4e6b64b;p=platform%2Fupstream%2Flibxslt.git - functions.[ch]: Bjorn Reese 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 --- diff --git a/ChangeLog b/ChangeLog index f64ecb3..9c22ac3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Thu Jan 25 12:13:04 CET 2001 Daniel Veillard + + * functions.[ch]: Bjorn Reese 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 * libxslt/xsltInternals.h libxslt/pattern.c: fixed problems diff --git a/FEATURES b/FEATURES index 651e570..9356fac 100644 --- a/FEATURES +++ b/FEATURES @@ -203,7 +203,7 @@ Functions: NO node-set document(object, node-set?) 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 string unparsed-entity-uri(string) NO string generate-id(node-set?) diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000..f00b312 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,5 @@ +#undef HAVE_ISINF +#undef HAVE_ISNAN +#undef HAVE_POW +#undef HAVE_FLOOR +#undef HAVE_FABS diff --git a/config.h.in b/config.h.in index be5dcb9..0c922c0 100644 --- a/config.h.in +++ b/config.h.in @@ -5,3 +5,24 @@ /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS + +#undef HAVE_ISINF +#undef HAVE_ISNAN +#undef HAVE_POW +#undef HAVE_FLOOR +#undef HAVE_FABS + +/* Define if you have the header file. */ +#undef HAVE_FLOAT_H + +/* Define if you have the header file. */ +#undef HAVE_FP_CLASS_H + +/* Define if you have the header file. */ +#undef HAVE_IEEEFP_H + +/* Define if you have the header file. */ +#undef HAVE_MATH_H + +/* Define if you have the header file. */ +#undef HAVE_NAN_H diff --git a/configure.in b/configure.in index 7b34d95..6696891 100644 --- a/configure.in +++ b/configure.in @@ -8,6 +8,37 @@ AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define) AM_MAINTAINER_MODE 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 if test "${LOGNAME}" = "veillard" -a "`pwd`" = "/u/veillard/XSLT" ; then @@ -49,16 +80,6 @@ AC_ARG_WITH(libxml-libs-prefix, ) -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 dnl ALL_LINGUAS="it ko fr de es no ga sv pt ja fi cs" @@ -110,10 +131,12 @@ AC_SUBST(LIBXML_CFLAGS) XSLT_LIBDIR='-L${libdir}' 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_INCLUDEDIR) +AC_SUBST(EXTRA_LIBS) AC_SUBST(XSLT_LIBS) AC_OUTPUT([ diff --git a/libxslt/Makefile.am b/libxslt/Makefile.am index 1f4724e..6036591 100644 --- a/libxslt/Makefile.am +++ b/libxslt/Makefile.am @@ -32,7 +32,7 @@ libxslt_la_SOURCES = \ bin_PROGRAMS = xsltproc 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_LDFLAGS = diff --git a/libxslt/functions.c b/libxslt/functions.c index 9eb48bf..ca041c2 100644 --- a/libxslt/functions.c +++ b/libxslt/functions.c @@ -7,13 +7,34 @@ * See Copyright for the status of this software. * * Daniel.Veillard@imag.fr + * Bjorn Reese for number formatting */ #include "xsltconfig.h" #include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_MATH_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_IEEEFP_H +#include +#endif +#ifdef HAVE_NAN_H +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#endif + #include +#include #include #include #include @@ -28,6 +49,50 @@ #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,9 +147,245 @@ xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){ * Implement the format-number() XSLT function * 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 -xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs){ - TODO /* function */ +xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + 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); } /** diff --git a/libxslt/functions.h b/libxslt/functions.h index 67d3208..b043451 100644 --- a/libxslt/functions.h +++ b/libxslt/functions.h @@ -4,6 +4,7 @@ * See Copyright for the status of this software. * * Daniel.Veillard@imag.fr + * Bjorn Reese for number formatting */ #ifndef __XML_XSLT_FUNCTIONS_H__ @@ -18,6 +19,25 @@ extern "C" { #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 */ diff --git a/tests/Makefile.am b/tests/Makefile.am index b463578..26fe50a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -2,3 +2,4 @@ SUBDIRS=REC1 REC2 +test tests: all