Back to index

lightning-sunbird  0.9+nobinonly
NumberFunctionCall.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * The MITRE Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * NumberFunctionCall
00040  * A representation of the XPath Number funtions
00041  */
00042 
00043 #include "FunctionLib.h"
00044 #include <math.h>
00045 #include "txNodeSet.h"
00046 #include "txAtoms.h"
00047 #include "txIXPathContext.h"
00048 
00049 /*
00050  * Creates a NumberFunctionCall of the given type
00051  */
00052 NumberFunctionCall::NumberFunctionCall(NumberFunctions aType)
00053     : mType(aType)
00054 {
00055 }
00056 
00057 /*
00058  * Evaluates this Expr based on the given context node and processor state
00059  * @param context the context Node for evaluation of this Expr
00060  * @param ps      the ContextState containing the stack information needed
00061  *                for evaluation
00062  * @return the result of the evaluation
00063  */
00064 nsresult
00065 NumberFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
00066 {
00067     *aResult = nsnull;
00068 
00069     txListIterator iter(&params);
00070     if (mType == NUMBER) {
00071         if (!requireParams(0, 1, aContext))
00072             return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00073     }
00074     else {
00075         if (!requireParams(1, 1, aContext))
00076             return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00077     }
00078 
00079     switch (mType) {
00080         case CEILING:
00081         {
00082             double dbl = evaluateToNumber((Expr*)iter.next(), aContext);
00083             if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) {
00084                 if (Double::isNeg(dbl) && dbl > -1) {
00085                     dbl *= 0;
00086                 }
00087                 else {
00088                     dbl = ceil(dbl);
00089                 }
00090             }
00091 
00092             return aContext->recycler()->getNumberResult(dbl, aResult);
00093         }
00094         case FLOOR:
00095         {
00096             double dbl = evaluateToNumber((Expr*)iter.next(), aContext);
00097             if (!Double::isNaN(dbl) &&
00098                 !Double::isInfinite(dbl) &&
00099                 !(dbl == 0 && Double::isNeg(dbl))) {
00100                 dbl = floor(dbl);
00101             }
00102 
00103             return aContext->recycler()->getNumberResult(dbl, aResult);
00104         }
00105         case ROUND:
00106         {
00107             double dbl = evaluateToNumber((Expr*)iter.next(), aContext);
00108             if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) {
00109                 if (Double::isNeg(dbl) && dbl >= -0.5) {
00110                     dbl *= 0;
00111                 }
00112                 else {
00113                     dbl = floor(dbl + 0.5);
00114                 }
00115             }
00116 
00117             return aContext->recycler()->getNumberResult(dbl, aResult);
00118         }
00119         case SUM:
00120         {
00121             nsRefPtr<txNodeSet> nodes;
00122             nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
00123                                             getter_AddRefs(nodes));
00124             NS_ENSURE_SUCCESS(rv, rv);
00125 
00126             double res = 0;
00127             PRInt32 i;
00128             for (i = 0; i < nodes->size(); ++i) {
00129                 nsAutoString resultStr;
00130                 txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
00131                 res += Double::toDouble(resultStr);
00132             }
00133             return aContext->recycler()->getNumberResult(res, aResult);
00134         }
00135         case NUMBER:
00136         {
00137             double res;
00138             if (iter.hasNext()) {
00139                 res = evaluateToNumber((Expr*)iter.next(), aContext);
00140             }
00141             else {
00142                 nsAutoString resultStr;
00143                 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
00144                                                   resultStr);
00145                 res = Double::toDouble(resultStr);
00146             }
00147             return aContext->recycler()->getNumberResult(res, aResult);
00148         }
00149     }
00150 
00151     aContext->receiveError(NS_LITERAL_STRING("Internal error"),
00152                            NS_ERROR_UNEXPECTED);
00153     return NS_ERROR_UNEXPECTED;
00154 }
00155 
00156 #ifdef TX_TO_STRING
00157 nsresult
00158 NumberFunctionCall::getNameAtom(nsIAtom** aAtom)
00159 {
00160     switch (mType) {
00161         case NUMBER:
00162         {
00163             *aAtom = txXPathAtoms::number;
00164             break;
00165         }
00166         case ROUND:
00167         {
00168             *aAtom = txXPathAtoms::round;
00169             break;
00170         }
00171         case FLOOR:
00172         {
00173             *aAtom = txXPathAtoms::floor;
00174             break;
00175         }
00176         case CEILING:
00177         {
00178             *aAtom = txXPathAtoms::ceiling;
00179             break;
00180         }
00181         case SUM:
00182         {
00183             *aAtom = txXPathAtoms::sum;
00184             break;
00185         }
00186         default:
00187         {
00188             *aAtom = 0;
00189             return NS_ERROR_FAILURE;
00190         }
00191     }
00192     NS_ADDREF(*aAtom);
00193     return NS_OK;
00194 }
00195 #endif