Cleanup BooleanFunctionCall and StringFunctionCall, fixes bugs in lang(), substring() and a few more.

b=104758 r=Pike sr=jag
This commit is contained in:
sicking%bigfoot.com 2002-01-28 14:46:39 +00:00
parent d89447a076
commit 0a836b98e9
7 changed files with 380 additions and 320 deletions

View File

@ -1,4 +1,5 @@
/*
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
@ -32,9 +33,10 @@
/**
* Creates a default BooleanFunctionCall, which always evaluates to False
**/
BooleanFunctionCall::BooleanFunctionCall(short type) : FunctionCall()
BooleanFunctionCall::BooleanFunctionCall(BooleanFunctions aType)
: mType(aType)
{
switch ( type ) {
switch (aType) {
case TX_BOOLEAN :
name = XPathNames::BOOLEAN_FN;
break;
@ -51,7 +53,6 @@ BooleanFunctionCall::BooleanFunctionCall(short type) : FunctionCall()
name = XPathNames::FALSE_FN;
break;
}
this->type = type;
} //-- BooleanFunctionCall
/**
@ -61,49 +62,77 @@ BooleanFunctionCall::BooleanFunctionCall(short type) : FunctionCall()
* for evaluation
* @return the result of the evaluation
**/
ExprResult* BooleanFunctionCall::evaluate(Node* context, ContextState* cs) {
ExprResult* BooleanFunctionCall::evaluate(Node* aContext, ContextState* aCs)
{
ListIterator iter(&params);
MBool result = MB_FALSE;
ListIterator* iter = params.iterator();
Expr* param = 0;
String err;
switch (mType) {
case TX_BOOLEAN:
{
if (!requireParams(1, 1, aCs))
return new StringResult("error");
switch ( type ) {
case TX_BOOLEAN :
if ( requireParams(1,1,cs) ) {
param = (Expr*)iter->next();
ExprResult* exprResult = param->evaluate(context, cs);
result = exprResult->booleanValue();
delete exprResult;
}
break;
return new BooleanResult(evaluateToBoolean((Expr*)iter.next(),
aContext,
aCs));
}
case TX_LANG:
if ( requireParams(1,1,cs) ) {
String arg1, lang;
evaluateToString((Expr*)iter->next(),context, cs, arg1);
((Element*)context)->getAttr(txXMLAtoms::lang,
kNameSpaceID_XML, lang);
arg1.toUpperCase(); // case-insensitive comparison
lang.toUpperCase();
result = (MBool)(lang.indexOf(arg1) == 0);
}
break;
case TX_NOT :
if ( requireParams(1,1,cs) ) {
param = (Expr*)iter->next();
ExprResult* exprResult = param->evaluate(context, cs);
result = (MBool)(!exprResult->booleanValue());
delete exprResult;
}
break;
case TX_TRUE :
result = MB_TRUE;
break;
default:
break;
}
delete iter;
return new BooleanResult(result);
} //-- evaluate
{
if (!requireParams(1, 1, aCs))
return new StringResult("error");
String lang;
Node* node = aContext;
while (node) {
if (node->getNodeType() == Node::ELEMENT_NODE) {
Element* elem = (Element*)node;
if (elem->getAttr(txXMLAtoms::lang,
kNameSpaceID_XML, lang))
break;
}
node = node->getParentNode();
}
MBool result = MB_FALSE;
if (node) {
String arg;
evaluateToString((Expr*)iter.next(),aContext, aCs, arg);
arg.toUpperCase(); // case-insensitive comparison
lang.toUpperCase();
result = lang.indexOf(arg) == 0 &&
(lang.length() == arg.length() ||
lang.charAt(arg.length()) == '-');
}
return new BooleanResult(result);
}
case TX_NOT:
{
if (!requireParams(1, 1, aCs))
return new StringResult("error");
return new BooleanResult(!evaluateToBoolean((Expr*)iter.next(),
aContext,
aCs));
}
case TX_TRUE:
{
if (!requireParams(0, 0, aCs))
return new StringResult("error");
return new BooleanResult(MB_TRUE);
}
case TX_FALSE:
{
if (!requireParams(0, 0, aCs))
return new StringResult("error");
return new BooleanResult(MB_FALSE);
}
}
String err("Internal error");
aCs->recieveError(err);
return new StringResult("error");
}

View File

@ -1,4 +1,5 @@
/*
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
@ -188,20 +189,25 @@ protected:
FunctionCall();
FunctionCall(const String& name);
/**
* Evaluates the given Expression and converts it's result to a String.
/*
* Evaluates the given Expression and converts its result to a String.
* The value is appended to the given destination String
**/
void evaluateToString
(Expr* expr, Node* context, ContextState* cs, String& dest);
/**
* Evaluates the given Expression and converts it's result to a number.
**/
double evaluateToNumber(Expr* expr, Node* context, ContextState* cs);
*/
void evaluateToString(Expr* aExpr, Node* aContext,
ContextState* aCs, String& aDest);
/*
* Evaluates the given Expression and converts it's result to a NodeSet.
* Evaluates the given Expression and converts its result to a number.
*/
double evaluateToNumber(Expr* aExpr, Node* aContext, ContextState* aCs);
/*
* Evaluates the given Expression and converts its result to a boolean.
*/
MBool evaluateToBoolean(Expr* aExpr, Node* aContext, ContextState* aCs);
/*
* Evaluates the given Expression and converts its result to a NodeSet.
* If the result is not a NodeSet NULL is returned.
*/
NodeSet* evaluateToNodeSet(Expr* aExpr, Node* aContext, ContextState* aCs);

View File

@ -110,34 +110,57 @@ MBool FunctionCall::matches(Node* node, Node* context, ContextState* cs)
return result;
} //-- matches
/**
* Evaluates the given Expression and converts it's result to a String.
/*
* Evaluates the given Expression and converts its result to a String.
* The value is appended to the given destination String
**/
void FunctionCall::evaluateToString(Expr* expr, Node* context,
ContextState* cs, String& dest)
*/
void FunctionCall::evaluateToString(Expr* aExpr,
Node* aContext,
ContextState* aCs,
String& aDest)
{
if (!expr)
NS_ASSERTION(aExpr, "missing expression");
ExprResult* exprResult = aExpr->evaluate(aContext, aCs);
if (!exprResult)
return;
ExprResult* exprResult = expr->evaluate(context, cs);
exprResult->stringValue(dest);
delete exprResult;
} //-- evaluateToString
/**
* Evaluates the given Expression and converts it's result to a number.
**/
double FunctionCall::evaluateToNumber(Expr* expr, Node* context,
ContextState* cs)
exprResult->stringValue(aDest);
delete exprResult;
}
/*
* Evaluates the given Expression and converts its result to a number.
*/
double FunctionCall::evaluateToNumber(Expr* aExpr,
Node* aContext,
ContextState* aCs)
{
double result = Double::NaN;
if (!expr)
return result;
ExprResult* exprResult = expr->evaluate(context, cs);
result = exprResult->numberValue();
NS_ASSERTION(aExpr, "missing expression");
ExprResult* exprResult = aExpr->evaluate(aContext, aCs);
if (!exprResult)
return Double::NaN;
double result = exprResult->numberValue();
delete exprResult;
return result;
} //-- evaluateToNumber
}
/*
* Evaluates the given Expression and converts its result to a boolean.
*/
MBool FunctionCall::evaluateToBoolean(Expr* aExpr,
Node* aContext,
ContextState* aCs)
{
NS_ASSERTION(aExpr, "missing expression");
ExprResult* exprResult = aExpr->evaluate(aContext, aCs);
if (!exprResult)
return MB_FALSE;
MBool result = exprResult->booleanValue();
delete exprResult;
return result;
}
/*
* Evaluates the given Expression and converts its result to a NodeSet.
@ -148,7 +171,6 @@ NodeSet* FunctionCall::evaluateToNodeSet(Expr* aExpr,
ContextState* aCs)
{
NS_ASSERTION(aExpr, "Missing expression to evaluate");
ExprResult* exprResult = aExpr->evaluate(aContext, aCs);
if (!exprResult)
return 0;

View File

@ -112,12 +112,18 @@ class BooleanFunctionCall : public FunctionCall {
public:
enum booleanFunctions { TX_BOOLEAN = 1, TX_FALSE, TX_LANG, TX_NOT, TX_TRUE };
enum BooleanFunctions {
TX_BOOLEAN, // boolean()
TX_FALSE, // false()
TX_LANG, // lang()
TX_NOT, // not()
TX_TRUE // true()
};
/**
* Creates a BooleanFunctionCall of the given type
**/
BooleanFunctionCall(short type);
BooleanFunctionCall(BooleanFunctions aType);
/**
* Evaluates this Expr based on the given context node and processor state
@ -126,10 +132,10 @@ public:
* for evaluation
* @return the result of the evaluation
**/
virtual ExprResult* evaluate(Node* context, ContextState* cs);
ExprResult* evaluate(Node* aContext, ContextState* aCs);
private:
short type;
BooleanFunctions mType;
}; //-- BooleanFunctionCall
/**
@ -271,7 +277,7 @@ public:
* for evaluation
* @return the result of the evaluation
*/
virtual ExprResult* evaluate(Node* context, ContextState* cs);
ExprResult* evaluate(Node* aContext, ContextState* aCs);
private:
NodeSetFunctions mType;
@ -285,23 +291,23 @@ class StringFunctionCall : public FunctionCall {
public:
enum stringFunctions {
CONCAT = 1, //-- concat()
CONTAINS, //-- contains()
NORMALIZE_SPACE, //-- normalize-space()
STARTS_WITH, //-- starts-with()
STRING, //-- string()
STRING_LENGTH, //-- string-length()
SUBSTRING, //-- substring()
SUBSTRING_AFTER, //-- substring-after()
SUBSTRING_BEFORE, //-- substring-before()
TRANSLATE //-- translate()
enum StringFunctions {
CONCAT, // concat()
CONTAINS, // contains()
NORMALIZE_SPACE, // normalize-space()
STARTS_WITH, // starts-with()
STRING, // string()
STRING_LENGTH, // string-length()
SUBSTRING, // substring()
SUBSTRING_AFTER, // substring-after()
SUBSTRING_BEFORE, // substring-before()
TRANSLATE // translate()
};
/**
* Creates a String function of the given type
**/
StringFunctionCall(short type);
StringFunctionCall(StringFunctions aType);
/**
* Evaluates this Expr based on the given context node and processor state
@ -310,10 +316,10 @@ public:
* for evaluation
* @return the result of the evaluation
**/
virtual ExprResult* evaluate(Node* context, ContextState* cs);
ExprResult* evaluate(Node* aContext, ContextState* aCs);
private:
short type;
StringFunctions mType;
}; //-- StringFunctionCall
@ -335,7 +341,7 @@ public:
/*
* Creates a Number function of the given type
*/
NumberFunctionCall(NumberFunctions type);
NumberFunctionCall(NumberFunctions aType);
/*
* Evaluates this Expr based on the given context node and processor state
@ -344,7 +350,7 @@ public:
* for evaluation
* @return the result of the evaluation
*/
virtual ExprResult* evaluate(Node* context, ContextState* cs);
ExprResult* evaluate(Node* aContext, ContextState* aCs);
private:
NumberFunctions mType;

View File

@ -68,22 +68,23 @@ NumberFunctionCall::NumberFunctionCall(NumberFunctions aType) {
* for evaluation
* @return the result of the evaluation
*/
ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
ExprResult* NumberFunctionCall::evaluate(Node* aContext, ContextState* aCs)
{
ListIterator iter(&params);
if (mType == NUMBER) {
if (!requireParams(0, 1, cs))
if (!requireParams(0, 1, aCs))
return new StringResult("error");
}
else {
if (!requireParams(1, 1, cs))
if (!requireParams(1, 1, aCs))
return new StringResult("error");
}
switch (mType) {
case CEILING:
{
double dbl = evaluateToNumber((Expr*)iter.next(), context, cs);
double dbl = evaluateToNumber((Expr*)iter.next(), aContext, aCs);
if (Double::isNaN(dbl) || Double::isInfinite(dbl))
return new NumberResult(dbl);
@ -94,7 +95,7 @@ ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
}
case FLOOR:
{
double dbl = evaluateToNumber((Expr*)iter.next(), context, cs);
double dbl = evaluateToNumber((Expr*)iter.next(), aContext, aCs);
if (Double::isNaN(dbl) ||
Double::isInfinite(dbl) ||
(dbl == 0 && Double::isNeg(dbl)))
@ -104,7 +105,7 @@ ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
}
case ROUND:
{
double dbl = evaluateToNumber((Expr*)iter.next(), context, cs);
double dbl = evaluateToNumber((Expr*)iter.next(), aContext, aCs);
if (Double::isNaN(dbl) || Double::isInfinite(dbl))
return new NumberResult(dbl);
@ -116,7 +117,7 @@ ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
case SUM:
{
NodeSet* nodes;
nodes = evaluateToNodeSet((Expr*)iter.next(), context, cs);
nodes = evaluateToNodeSet((Expr*)iter.next(), aContext, aCs);
if (!nodes)
return new StringResult("error");
@ -134,14 +135,18 @@ ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
}
case NUMBER:
{
if (iter.hasNext())
if (iter.hasNext()) {
return new NumberResult(
evaluateToNumber((Expr*)iter.next(), context, cs));
evaluateToNumber((Expr*)iter.next(), aContext, aCs));
}
String resultStr;
XMLDOMUtils::getNodeValue(context, resultStr);
XMLDOMUtils::getNodeValue(aContext, resultStr);
return new NumberResult(Double::toDouble(resultStr));
}
}
String err("Internal error");
aCs->recieveError(err);
return new StringResult("error");
}

View File

@ -1,4 +1,5 @@
/*
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
@ -29,16 +30,15 @@
**/
#include "FunctionLib.h"
#include "XMLUtils.h"
#include "XMLDOMUtils.h"
#include <math.h>
/**
* Creates a StringFunctionCall of the given type
**/
StringFunctionCall::StringFunctionCall(short type) : FunctionCall() {
this->type = type;
switch ( type ) {
StringFunctionCall::StringFunctionCall(StringFunctions aType) : mType(aType)
{
switch (aType) {
case CONCAT:
name = XPathNames::CONCAT_FN;
break;
@ -67,7 +67,7 @@ StringFunctionCall::StringFunctionCall(short type) : FunctionCall() {
name = XPathNames::STRING_FN;
break;
}
} //-- StringFunctionCall
}
/**
* Evaluates this Expr based on the given context node and processor state
@ -76,214 +76,202 @@ StringFunctionCall::StringFunctionCall(short type) : FunctionCall() {
* for evaluation
* @return the result of the evaluation
**/
ExprResult* StringFunctionCall::evaluate(Node* context, ContextState* cs) {
ListIterator* iter = params.iterator();
PRInt32 argc = params.getLength();
String err;
ExprResult* result = 0;
switch ( type ) {
case CONCAT :
if ( requireParams(2, cs) ) {
String resultStr;
while(iter->hasNext()) {
evaluateToString((Expr*)iter->next(),context, cs, resultStr);
}
result = new StringResult(resultStr);
ExprResult* StringFunctionCall::evaluate(Node* aContext, ContextState* aCs)
{
ListIterator iter(&params);
switch (mType) {
case CONCAT:
{
if (!requireParams(2, aCs))
return new StringResult("error");
String resultStr;
while (iter.hasNext()) {
evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr);
}
else result = new StringResult("");
break;
case CONTAINS :
if ( requireParams(2, 2, cs) ) {
String arg1, arg2;
evaluateToString((Expr*)iter->next(),context, cs, arg1);
evaluateToString((Expr*)iter->next(),context, cs, arg2);
result = new BooleanResult((MBool)(arg1.indexOf(arg2) >= 0));
}
else result = new BooleanResult(MB_FALSE);
break;
return new StringResult(resultStr);
}
case CONTAINS:
{
if (!requireParams(2, 2, aCs))
return new StringResult("error");
String arg1, arg2;
evaluateToString((Expr*)iter.next(), aContext, aCs, arg1);
evaluateToString((Expr*)iter.next(), aContext, aCs, arg2);
return new BooleanResult(arg1.indexOf(arg2) >= 0);
}
case NORMALIZE_SPACE:
if ( requireParams(0, 1, cs) ) {
String resultStr;
if ( argc == 1)
evaluateToString((Expr*)iter->next(),context, cs, resultStr);
else
XMLDOMUtils::getNodeValue(context, resultStr);
// Leading & Trailing Whitespace
resultStr.trim();
MBool hasSpace = MB_FALSE;
PRInt32 dest=0;
String normed(resultStr.length());
UNICODE_CHAR current;
for (PRInt32 src=0; src<resultStr.length(); src++) {
current=resultStr.charAt(src);
if (current==' ' || current=='\n' ||
current=='\t' || current=='\r') {
if (!hasSpace) {
normed.replace(dest,' ');
dest++;
hasSpace=MB_TRUE;
}
}
else {
normed.replace(dest,current);
dest++;
hasSpace=MB_FALSE;
}
}
result = new StringResult(normed);
}
else result = new StringResult("");
break;
case STARTS_WITH :
if ( requireParams(2, 2, cs) ) {
String arg1, arg2;
evaluateToString((Expr*)iter->next(),context, cs, arg1);
evaluateToString((Expr*)iter->next(),context, cs, arg2);
result = new BooleanResult((MBool)(arg1.indexOf(arg2) == 0));
}
else result = new BooleanResult(MB_FALSE);
break;
case STRING_LENGTH:
if ( requireParams(0, 1, cs) ) {
String resultStr;
if ( argc == 1) {
evaluateToString((Expr*)iter->next(),context, cs, resultStr);
}
else XMLDOMUtils::getNodeValue(context, resultStr);
result = new NumberResult( (double) resultStr.length());
}
else result = new NumberResult(0.0);
break;
case SUBSTRING:
if ( requireParams(2, 3, cs) ) {
String src;
evaluateToString((Expr*)iter->next(),context, cs, src);
double dbl = evaluateToNumber((Expr*)iter->next(), context, cs);
{
if (!requireParams(0, 1, aCs))
return new StringResult("error");
//-- check for NaN
if ( Double::isNaN(dbl)) {
result = new StringResult("");
break;
}
//-- check for -Infinity
MBool startsNegInf = (dbl==Double::NEGATIVE_INFINITY);
PRInt32 startIdx = startsNegInf?0:(PRInt32)floor(dbl+.5);
PRInt32 endIdx = src.length()+1;
if ( argc == 3) {
dbl = evaluateToNumber((Expr*)iter->next(),context, cs);
if (startsNegInf) {
result = new StringResult("");
break;
}
if (dbl == Double::POSITIVE_INFINITY) ; //already complete
else if ( Double::isNaN(dbl) ||
dbl == Double::NEGATIVE_INFINITY ||
dbl < 0 )
endIdx = 0;
else endIdx = startIdx+(PRInt32)floor(dbl+.5);
}
String resultStr;
//-- strings are indexed starting at 1 for XSL
//-- adjust to a 0-based index
endIdx--;
if (startIdx<1){
startIdx = 0;
} else {
startIdx--;
}
src.subString(startIdx,endIdx,resultStr);
result = new StringResult(resultStr);
}
else result = new StringResult("");
break;
case SUBSTRING_AFTER:
if ( requireParams(2, 2, cs) ) {
String arg1, arg2;
evaluateToString((Expr*)iter->next(),context, cs, arg1);
evaluateToString((Expr*)iter->next(),context, cs, arg2);
PRInt32 idx = arg1.indexOf(arg2);
if ((idx >= 0)&&(idx<arg1.length())) {
PRInt32 len = arg2.length();
arg2.clear();
arg1.subString(idx+len,arg2);
result = new StringResult(arg2);
break;
}
}
result = new StringResult("");
break;
case SUBSTRING_BEFORE:
if ( requireParams(2, 2, cs) ) {
String arg1, arg2;
evaluateToString((Expr*)iter->next(),context, cs, arg1);
evaluateToString((Expr*)iter->next(),context, cs, arg2);
PRInt32 idx = arg1.indexOf(arg2);
if ((idx >= 0)&&(idx<arg1.length())) {
arg2.clear();
arg1.subString(0,idx,arg2);
result = new StringResult(arg2);
break;
}
}
result = new StringResult("");
break;
case TRANSLATE:
if ( requireParams(3, 3, cs) ) {
String src;
evaluateToString((Expr*)iter->next(),context, cs, src);
if (src.isEmpty()) {
result = new StringResult("");
break;
}
String oldChars, newChars;
evaluateToString((Expr*)iter->next(),context, cs, oldChars);
evaluateToString((Expr*)iter->next(),context, cs, newChars);
PRInt32 size = src.length();
UNICODE_CHAR* chars = src.toUnicode(new UNICODE_CHAR[size]);
src.clear();
PRInt32 i;
for (i = 0; i < size; i++) {
PRInt32 idx = oldChars.indexOf(chars[i]);
if (idx >= 0) {
if (idx < newChars.length())
src.append(newChars.charAt(idx));
}
else {
src.append(chars[i]);
}
}
delete chars;
result = new StringResult(src);
}
String resultStr;
if (iter.hasNext())
evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr);
else
result = new StringResult("");
break;
XMLDOMUtils::getNodeValue(aContext, resultStr);
default : //-- string( object? )
if ( requireParams(0, 1, cs) ) {
String resultStr;
if (iter->hasNext()) {
evaluateToString((Expr*)iter->next(),context, cs, resultStr);
MBool addSpace = MB_FALSE;
MBool first = MB_TRUE;
String normed(resultStr.length());
UNICODE_CHAR c;
PRInt32 src;
for (src = 0; src < resultStr.length(); src++) {
c = resultStr.charAt(src);
if (c == ' ' || c == '\n' ||
c == '\t' || c == '\r') {
addSpace = MB_TRUE;
}
else {
XMLDOMUtils::getNodeValue(context, resultStr);
if ( cs->isStripSpaceAllowed(context) &&
XMLUtils::shouldStripTextnode(resultStr))
resultStr = "";
}
result = new StringResult(resultStr);
}
else result = new StringResult("");
break;
}
delete iter;
return result;
} //-- evaluate
if (addSpace && !first)
normed.append(' ');
normed.append(c);
addSpace = MB_FALSE;
first = MB_FALSE;
}
}
return new StringResult(normed);
}
case STARTS_WITH:
{
if (!requireParams(2, 2, aCs))
return new StringResult("error");
String arg1, arg2;
evaluateToString((Expr*)iter.next(), aContext, aCs, arg1);
evaluateToString((Expr*)iter.next(), aContext, aCs, arg2);
return new BooleanResult(arg1.indexOf(arg2) == 0);
}
case STRING_LENGTH:
{
if (!requireParams(0, 1, aCs))
return new StringResult("error");
String resultStr;
if (iter.hasNext())
evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr);
else
XMLDOMUtils::getNodeValue(aContext, resultStr);
return new NumberResult(resultStr.length());
}
case SUBSTRING:
{
if (!requireParams(2, 3, aCs))
return new StringResult("error");
String src;
double start, end;
evaluateToString((Expr*)iter.next(), aContext, aCs, src);
start = evaluateToNumber((Expr*)iter.next(), aContext, aCs);
// check for NaN or +/-Inf
if (Double::isNaN(start) ||
Double::isInfinite(start) ||
start + 0.5 >= src.length())
return new StringResult();
start = floor(start + 0.5) - 1;
if (iter.hasNext()) {
end = start + evaluateToNumber((Expr*)iter.next(),
aContext,
aCs);
if (Double::isNaN(end) || end < 0)
return new StringResult();
if (end > src.length())
end = src.length();
else
end = floor(end + 0.5);
}
else {
end = src.length();
}
if (start < 0)
start = 0;
if (start > end)
return new StringResult();
String resultStr;
src.subString((PRInt32)start, (PRInt32)end, resultStr);
return new StringResult(resultStr);
}
case SUBSTRING_AFTER:
{
if (!requireParams(2, 2, aCs))
return new StringResult("error");
String arg1, arg2;
evaluateToString((Expr*)iter.next(), aContext, aCs, arg1);
evaluateToString((Expr*)iter.next(), aContext, aCs, arg2);
PRInt32 idx = arg1.indexOf(arg2);
if (idx >= 0) {
PRInt32 len = arg2.length();
arg1.subString(idx + len, arg2);
return new StringResult(arg2);
}
return new StringResult();
}
case SUBSTRING_BEFORE:
{
if (!requireParams(2, 2, aCs))
return new StringResult("error");
String arg1, arg2;
evaluateToString((Expr*)iter.next(), aContext, aCs, arg1);
evaluateToString((Expr*)iter.next(), aContext, aCs, arg2);
PRInt32 idx = arg1.indexOf(arg2);
if (idx >= 0) {
arg2.clear();
arg1.subString(0, idx, arg2);
return new StringResult(arg2);
}
return new StringResult();
}
case TRANSLATE:
{
if (!requireParams(3, 3, aCs))
return new StringResult("error");
String src;
evaluateToString((Expr*)iter.next(), aContext, aCs, src);
if (src.isEmpty())
return new StringResult();
String oldChars, newChars, dest;
evaluateToString((Expr*)iter.next(), aContext, aCs, oldChars);
evaluateToString((Expr*)iter.next(), aContext, aCs, newChars);
PRInt32 i;
for (i = 0; i < src.length(); i++) {
PRInt32 idx = oldChars.indexOf(src.charAt(i));
if (idx >= 0) {
if (idx < newChars.length())
dest.append(newChars.charAt(idx));
}
else {
dest.append(src.charAt(i));
}
}
return new StringResult(dest);
}
case STRING:
{
if (!requireParams(0, 1, aCs))
return new StringResult("error");
String resultStr;
if (iter.hasNext())
evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr);
else
XMLDOMUtils::getNodeValue(aContext, resultStr);
return new StringResult(resultStr);
}
}
String err("Internal error");
aCs->recieveError(err);
return new StringResult("error");
}

View File

@ -296,8 +296,12 @@ ExprResult* txFormatNumberFunctionCall::evaluate(Node* aContext,
return new StringResult;
}
int totalSize = minIntegerSize + maxFractionSize;
if (maxFractionSize > 0)
totalSize++; //to account for decimal point
char formatBuf[30];
sprintf(formatBuf, "%%0%d.%df", minIntegerSize, maxFractionSize);
sprintf(formatBuf, "%%0%d.%df", totalSize, maxFractionSize);
sprintf(buf, formatBuf, value);