mirror of
https://gitlab.gnome.org/GNOME/libxslt
synced 2025-11-05 12:10:38 +03:00
reworked internal representation of tokenized number format and
* libxslt/numbers.c: reworked internal representation of tokenized number format and parsing/tokenization. This fixes many bugs regarding separator and default tokens. * tests/REC/test-7.7-3.out: the fix changes the output of this test. It now complies to the XSLT spec (wow! ;o)
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
Wed Oct 17 02:46:55 CEST 2001 Thomas Broyer <tbroyer@ltgt.net>
|
||||
|
||||
* libxslt/numbers.c: reworked internal representation of
|
||||
tokenized number format and parsing/tokenization. This fixes
|
||||
many bugs regarding separator and default tokens.
|
||||
* tests/REC/test-7.7-3.out: the fix changes the output of this
|
||||
test. It now complies to the XSLT spec (wow! ;o)
|
||||
|
||||
Tue Oct 16 11:25:15 CEST 2001 Daniel Veillard <daniel@veillard.com>
|
||||
|
||||
* xsltproc/Makefile.am configure.in config.h.in: trying to
|
||||
|
||||
@@ -30,17 +30,33 @@
|
||||
# define TRUE (1 == 1)
|
||||
#endif
|
||||
|
||||
#define SYMBOL_QUOTE ((xmlChar)'\'')
|
||||
#define SYMBOL_QUOTE ((xmlChar)'\'')
|
||||
|
||||
typedef struct _xsltNumberFormatToken {
|
||||
xmlChar token;
|
||||
int width;
|
||||
xmlChar *filling;
|
||||
} xsltNumberFormatToken, *xsltNumberFormatTokenPtr;
|
||||
#define DEFAULT_TOKEN (xmlChar)'0'
|
||||
#define DEFAULT_SEPARATOR "."
|
||||
|
||||
#define MAX_TOKENS 1024
|
||||
|
||||
typedef struct _xsltFormatToken xsltFormatToken;
|
||||
typedef xsltFormatToken *xsltFormatTokenPtr;
|
||||
struct _xsltFormatToken {
|
||||
xmlChar *separator;
|
||||
xmlChar token;
|
||||
int width;
|
||||
};
|
||||
|
||||
typedef struct _xsltFormat xsltFormat;
|
||||
typedef xsltFormat *xsltFormatPtr;
|
||||
struct _xsltFormat {
|
||||
xmlChar *start;
|
||||
xsltFormatToken tokens[MAX_TOKENS];
|
||||
int nTokens;
|
||||
xmlChar *end;
|
||||
};
|
||||
|
||||
static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
static xsltNumberFormatToken default_token;
|
||||
static xsltFormatToken default_token;
|
||||
|
||||
|
||||
/************************************************************************
|
||||
@@ -194,58 +210,71 @@ xsltNumberFormatRoman(xmlBufferPtr buffer,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
xsltNumberFormatTokenize(xmlChar *format,
|
||||
xsltNumberFormatTokenPtr array,
|
||||
int array_max)
|
||||
xsltFormatPtr tokens)
|
||||
{
|
||||
int index = 0;
|
||||
int cnt;
|
||||
int j;
|
||||
|
||||
default_token.token = (xmlChar)'0';
|
||||
default_token.token = DEFAULT_TOKEN;
|
||||
default_token.width = 1;
|
||||
default_token.filling = BAD_CAST(".");
|
||||
default_token.separator = BAD_CAST(DEFAULT_SEPARATOR);
|
||||
|
||||
|
||||
tokens->start = NULL;
|
||||
tokens->tokens[0].separator = NULL;
|
||||
tokens->end = NULL;
|
||||
|
||||
/*
|
||||
* Parse initial non-alphanumeric token
|
||||
* Always use an empty token for that
|
||||
* Insert initial non-alphanumeric token.
|
||||
* There is always such a token in the list, even if NULL
|
||||
*/
|
||||
while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) {
|
||||
if (format[index] == 0)
|
||||
break; /* while */
|
||||
index++;
|
||||
if (format[index] == 0)
|
||||
break; /* while */
|
||||
index++;
|
||||
}
|
||||
if (index > 0)
|
||||
array[0].filling = xmlStrndup(format, index);
|
||||
else
|
||||
array[0].filling = NULL;
|
||||
tokens->start = xmlStrndup(format, index);
|
||||
|
||||
for (cnt = 1; cnt < array_max; cnt++) {
|
||||
if (format[index] == 0) {
|
||||
|
||||
for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS;
|
||||
tokens->nTokens++) {
|
||||
if (format[index] == 0)
|
||||
break; /* for */
|
||||
} else if (IS_DIGIT_ONE(format[index]) ||
|
||||
|
||||
/*
|
||||
* separator has already been parsed (except for the first
|
||||
* number) in tokens->end, recover it.
|
||||
*/
|
||||
if (tokens->nTokens > 0) {
|
||||
tokens->tokens[tokens->nTokens].separator = tokens->end;
|
||||
tokens->end = NULL;
|
||||
}
|
||||
|
||||
if (IS_DIGIT_ONE(format[index]) ||
|
||||
IS_DIGIT_ZERO(format[index])) {
|
||||
array[cnt].width = 1;
|
||||
tokens->tokens[tokens->nTokens].width = 1;
|
||||
while (IS_DIGIT_ZERO(format[index])) {
|
||||
array[cnt].width++;
|
||||
tokens->tokens[tokens->nTokens].width++;
|
||||
index++;
|
||||
}
|
||||
if (IS_DIGIT_ONE(format[index])) {
|
||||
array[cnt].token = format[index] - 1;
|
||||
tokens->tokens[tokens->nTokens].token = format[index] - 1;
|
||||
index++;
|
||||
}
|
||||
} else if (format[index] == (xmlChar)'A') {
|
||||
array[cnt].token = format[index];
|
||||
tokens->tokens[tokens->nTokens].token = format[index];
|
||||
index++;
|
||||
} else if (format[index] == (xmlChar)'a') {
|
||||
array[cnt].token = format[index];
|
||||
tokens->tokens[tokens->nTokens].token = format[index];
|
||||
index++;
|
||||
} else if (format[index] == (xmlChar)'I') {
|
||||
array[cnt].token = format[index];
|
||||
tokens->tokens[tokens->nTokens].token = format[index];
|
||||
index++;
|
||||
} else if (format[index] == (xmlChar)'i') {
|
||||
array[cnt].token = format[index];
|
||||
tokens->tokens[tokens->nTokens].token = format[index];
|
||||
index++;
|
||||
} else {
|
||||
/* XSLT section 7.7
|
||||
@@ -254,9 +283,8 @@ xsltNumberFormatTokenize(xmlChar *format,
|
||||
* not support a numbering sequence that starts with that
|
||||
* token, it must use a format token of 1."
|
||||
*/
|
||||
array[cnt].token = (xmlChar)'0';
|
||||
array[cnt].width = 1;
|
||||
index++;
|
||||
tokens->tokens[tokens->nTokens].token = (xmlChar)'0';
|
||||
tokens->tokens[tokens->nTokens].width = 1;
|
||||
}
|
||||
/*
|
||||
* Skip over remaining alphanumeric characters from the Nd
|
||||
@@ -269,8 +297,9 @@ xsltNumberFormatTokenize(xmlChar *format,
|
||||
*/
|
||||
while (IS_LETTER(format[index]) || IS_DIGIT(format[index]))
|
||||
index++;
|
||||
|
||||
/*
|
||||
* Insert non-alphanumeric separator.
|
||||
* Insert temporary non-alphanumeric final tooken.
|
||||
*/
|
||||
j = index;
|
||||
while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) {
|
||||
@@ -279,49 +308,53 @@ xsltNumberFormatTokenize(xmlChar *format,
|
||||
index++;
|
||||
}
|
||||
if (index > j)
|
||||
array[cnt].filling = xmlStrndup(&format[j], index - j);
|
||||
else
|
||||
array[cnt].filling = NULL;
|
||||
tokens->end = xmlStrndup(&format[j], index - j);
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
|
||||
double *numbers,
|
||||
int numbers_max,
|
||||
xsltNumberFormatToken (*array)[],
|
||||
int array_max,
|
||||
xsltFormatPtr tokens,
|
||||
xmlBufferPtr buffer)
|
||||
{
|
||||
int i = 0;
|
||||
int minmax;
|
||||
double number;
|
||||
xsltNumberFormatTokenPtr token;
|
||||
int is_last_default_token = 0;
|
||||
|
||||
minmax = (array_max >= numbers_max) ? numbers_max : array_max;
|
||||
xsltFormatTokenPtr token;
|
||||
|
||||
/*
|
||||
* Handle initial non-alphanumeric token
|
||||
*/
|
||||
token = &(*array)[0];
|
||||
if (token->filling != NULL)
|
||||
xmlBufferCat(buffer, token->filling);
|
||||
if (tokens->start != NULL)
|
||||
xmlBufferCat(buffer, tokens->start);
|
||||
|
||||
for (i = 0; i < numbers_max; i++) {
|
||||
/* Insert number */
|
||||
number = numbers[(numbers_max - 1) - i];
|
||||
if (i + 1 < array_max) {
|
||||
token = &(*array)[i + 1];
|
||||
} else if (array_max > 1) {
|
||||
token = &(*array)[array_max - 1];
|
||||
if (i < tokens->nTokens) {
|
||||
/* The "n"th format token will be used to format the "n"th
|
||||
* number in the list */
|
||||
token = &(tokens->tokens[i]);
|
||||
} else if (tokens->nTokens > 0) {
|
||||
/* If there are more numbers than format tokens, then the
|
||||
* last format token will be used to format the remaining
|
||||
* numbers. */
|
||||
token = &(tokens->tokens[tokens->nTokens - 1]);
|
||||
} else {
|
||||
/* If there are no format tokens, then a format token of
|
||||
* 1 is used to format all numbers. */
|
||||
token = &default_token;
|
||||
is_last_default_token = (i >= numbers_max - 1);
|
||||
}
|
||||
|
||||
|
||||
/* Print separator, except for the first number */
|
||||
if (i > 0) {
|
||||
if (token->separator != NULL)
|
||||
xmlBufferCat(buffer, token->separator);
|
||||
else
|
||||
xmlBufferCCat(buffer, DEFAULT_SEPARATOR);
|
||||
}
|
||||
|
||||
switch (xmlXPathIsInf(number)) {
|
||||
case -1:
|
||||
xmlBufferCCat(buffer, "-Infinity");
|
||||
@@ -373,10 +406,14 @@ xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((token->filling != NULL) && !is_last_default_token)
|
||||
xmlBufferCat(buffer, token->filling);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle final non-alphanumeric token
|
||||
*/
|
||||
if (tokens->end != NULL)
|
||||
xmlBufferCat(buffer, tokens->end);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -385,7 +422,6 @@ xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
|
||||
xmlChar *count,
|
||||
xmlChar *from,
|
||||
double *array,
|
||||
int max ATTRIBUTE_UNUSED,
|
||||
xmlDocPtr doc,
|
||||
xmlNodePtr elem)
|
||||
{
|
||||
@@ -574,9 +610,8 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
|
||||
xmlBufferPtr output = NULL;
|
||||
xmlNodePtr copy = NULL;
|
||||
int amount, i;
|
||||
int array_amount;
|
||||
double number;
|
||||
xsltNumberFormatToken array[1024];
|
||||
xsltFormat tokens;
|
||||
|
||||
if ((data->format == NULL) && (data->has_format != 0)) {
|
||||
data->format = xsltEvalAttrValueTemplate(ctxt, data->node,
|
||||
@@ -591,9 +626,7 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
|
||||
if (output == NULL)
|
||||
goto XSLT_NUMBER_FORMAT_END;
|
||||
|
||||
array_amount = xsltNumberFormatTokenize(data->format,
|
||||
array,
|
||||
sizeof(array)/sizeof(array[0]));
|
||||
xsltNumberFormatTokenize(data->format, &tokens);
|
||||
|
||||
/*
|
||||
* Evaluate the XPath expression to find the value(s)
|
||||
@@ -607,8 +640,7 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
|
||||
xsltNumberFormatInsertNumbers(data,
|
||||
&number,
|
||||
1,
|
||||
&array,
|
||||
array_amount,
|
||||
&tokens,
|
||||
output);
|
||||
}
|
||||
|
||||
@@ -627,8 +659,7 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
|
||||
xsltNumberFormatInsertNumbers(data,
|
||||
&number,
|
||||
1,
|
||||
&array,
|
||||
array_amount,
|
||||
&tokens,
|
||||
output);
|
||||
}
|
||||
} else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) {
|
||||
@@ -646,8 +677,7 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
|
||||
xsltNumberFormatInsertNumbers(data,
|
||||
numarray,
|
||||
amount,
|
||||
&array,
|
||||
array_amount,
|
||||
&tokens,
|
||||
output);
|
||||
}
|
||||
} else if (xmlStrEqual(data->level, (const xmlChar *) "any")) {
|
||||
@@ -655,16 +685,14 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
|
||||
node,
|
||||
data->count,
|
||||
data->from,
|
||||
&number,
|
||||
1,
|
||||
&number,
|
||||
data->doc,
|
||||
data->node);
|
||||
if (amount > 0) {
|
||||
xsltNumberFormatInsertNumbers(data,
|
||||
&number,
|
||||
1,
|
||||
&array,
|
||||
array_amount,
|
||||
&tokens,
|
||||
output);
|
||||
}
|
||||
}
|
||||
@@ -674,9 +702,14 @@ xsltNumberFormat(xsltTransformContextPtr ctxt,
|
||||
if (copy != NULL) {
|
||||
xmlAddChild(ctxt->insert, copy);
|
||||
}
|
||||
for (i = 0;i < array_amount;i++) {
|
||||
if (array[i].filling != NULL)
|
||||
xmlFree(array[i].filling);
|
||||
|
||||
if (tokens.start != NULL)
|
||||
xmlFree(tokens.start);
|
||||
if (tokens.end != NULL)
|
||||
xmlFree(tokens.end);
|
||||
for (i = 0;i < tokens.nTokens;i++) {
|
||||
if (tokens.tokens[i].separator != NULL)
|
||||
xmlFree(tokens.tokens[i].separator);
|
||||
}
|
||||
|
||||
XSLT_NUMBER_FORMAT_END:
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.First Chapter</fo:block>
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1 First Chapter</fo:block>
|
||||
Here is some text.
|
||||
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1 First Chapter, First Section</fo:block>
|
||||
More text here.
|
||||
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1 1 First Chapter, First Section, First Subsection</fo:block>
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1.1 First Chapter, First Section, First Subsection</fo:block>
|
||||
|
||||
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1 2 First Chapter, First Section, Second Subsection</fo:block>
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">1.1.2 First Chapter, First Section, Second Subsection</fo:block>
|
||||
|
||||
|
||||
|
||||
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">2.Second Chapter</fo:block>
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">2 Second Chapter</fo:block>
|
||||
|
||||
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">A.First Appendix</fo:block>
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">A First Appendix</fo:block>
|
||||
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">A.1 First Appendix, First Section</fo:block>
|
||||
|
||||
|
||||
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">B.Second Appendix</fo:block>
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">B Second Appendix</fo:block>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user