Back to index

lightning-sunbird  0.9+nobinonly
XFormsFunctionCall.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 Mozilla XForms support.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * IBM Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Aaron Reed <aaronr@us.ibm.com>
00024  *  Merle Sterling <msterlin@us.ibm.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 /*
00041  * XFormsFunctionCall
00042  * A representation of the XPath NodeSet funtions
00043  */
00044 
00045 #include "FunctionLib.h"
00046 #include "nsAutoPtr.h"
00047 #include "txNodeSet.h"
00048 #include "txAtoms.h"
00049 #include "txIXPathContext.h"
00050 #include "txTokenizer.h"
00051 #include "XFormsFunctions.h"
00052 #include <math.h>
00053 #include "nsIDOMDocument.h"
00054 #include "nsIDOMDocumentEvent.h"
00055 #include "nsIDOMEvent.h"
00056 #include "nsIDOMEventTarget.h"
00057 #include "nsIDOMElement.h"
00058 #include "nsIXFormsUtilityService.h"
00059 #include "nsServiceManagerUtils.h"  // needed for do_GetService?
00060 #include "prprf.h"
00061 #include "prrng.h"
00062 #include <errno.h>
00063 #include <stdlib.h>
00064 
00065 /*
00066  * Creates a XFormsFunctionCall of the given type
00067  */
00068 XFormsFunctionCall::XFormsFunctionCall(XFormsFunctions aType, nsIDOMNode *aNode)
00069     : mType(aType)
00070     , mNode(aNode)
00071 {
00072 }
00073 
00074 /*
00075  * Evaluates this Expr based on the given context node and processor state
00076  * @param context the context node for evaluation of this Expr
00077  * @param ps the ContextState containing the stack information needed
00078  * for evaluation
00079  * @return the result of the evaluation
00080  */
00081 nsresult
00082 XFormsFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
00083 {
00084   *aResult = nsnull;
00085   nsresult rv = NS_OK;
00086   txListIterator iter(&params);
00087 
00088   switch (mType) {
00089     case AVG:
00090     {
00091       if (!requireParams(1, 1, aContext))
00092         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00093 
00094       nsRefPtr<txNodeSet> nodes;
00095       nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
00096                                       getter_AddRefs(nodes));
00097       NS_ENSURE_SUCCESS(rv, rv);
00098    
00099       double res = 0;
00100       PRInt32 i;
00101       for (i = 0; i < nodes->size(); ++i) {
00102         nsAutoString resultStr;
00103         txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
00104         res += Double::toDouble(resultStr);
00105       }
00106    
00107       if (i > 0) {
00108         res = (res/i);
00109       }
00110       else {
00111         res = Double::NaN;
00112       }
00113       return aContext->recycler()->getNumberResult(res, aResult);
00114     }
00115     case BOOLEANFROMSTRING:
00116     {
00117       if (!requireParams(1, 1, aContext))
00118         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00119 
00120       PRInt32 retvalue = -1;
00121       nsAutoString booleanValue;
00122       evaluateToString((Expr*)iter.next(), aContext, booleanValue);
00123 
00124       aContext->recycler()->getBoolResult(
00125                                   booleanValue.EqualsLiteral("1") ||
00126                                   booleanValue.LowerCaseEqualsLiteral("true"), 
00127                                   aResult);
00128 
00129       return NS_OK;
00130     }
00131     case COUNTNONEMPTY:
00132     {
00133       if (!requireParams(1, 1, aContext))
00134         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00135 
00136       nsRefPtr<txNodeSet> nodes;
00137       nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
00138                                       getter_AddRefs(nodes));
00139       NS_ENSURE_SUCCESS(rv, rv);
00140    
00141       double res = 0, test = 0;
00142       PRInt32 i, count=0;
00143       for (i = 0; i < nodes->size(); ++i) {
00144         nsAutoString resultStr;
00145         txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
00146         if (!resultStr.IsEmpty()) {
00147           count++;
00148         }
00149       }
00150    
00151       return aContext->recycler()->getNumberResult(count, aResult);
00152     }
00153     case DAYSFROMDATE:
00154     {
00155       if (!requireParams(1, 1, aContext))
00156         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00157    
00158       nsAutoString date;
00159       evaluateToString((Expr*)iter.next(), aContext, date);
00160    
00161       nsCOMPtr<nsIXFormsUtilityService>xformsService = 
00162             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00163       NS_ENSURE_SUCCESS(rv, rv);
00164 
00165       PRInt32 result = 0;
00166       double res = Double::NaN;
00167       nsresult rv = xformsService->GetDaysFromDateTime(date, &result);
00168       if (NS_SUCCEEDED(rv)) {
00169         res = result;
00170       } 
00171       else if (rv != NS_ERROR_ILLEGAL_VALUE) {
00172         // if we failed for a reason other than the parameter value, pass that 
00173         // up the chain
00174         return rv;
00175       }
00176 
00177       return aContext->recycler()->getNumberResult(res, aResult);
00178     }
00179     case IF:
00180     {
00181       if (!requireParams(3, 3, aContext))
00182         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00183    
00184       PRBool test;
00185       nsAutoString valueToReturn;
00186       test = evaluateToBoolean((Expr*)iter.next(), aContext);
00187 
00188       // grab 'true' value to return
00189       Expr *getvalue = (Expr*)iter.next();
00190    
00191       if (!test) {
00192         // grab 'false' value to return
00193         getvalue = (Expr*)iter.next();
00194       }
00195       evaluateToString(getvalue, aContext, valueToReturn);
00196    
00197       return aContext->recycler()->getStringResult(valueToReturn, aResult);
00198     }
00199     case INDEX:
00200     {
00201       // Given an element's id as the parameter, need to query the element and 
00202       //   make sure that it is a xforms:repeat node.  Given that, must query 
00203       //   its index.
00204       if (!requireParams(1, 1, aContext))
00205           return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00206 
00207       nsAutoString indexId;
00208       evaluateToString((Expr*)iter.next(), aContext, indexId);
00209 
00210       // now get the index value from the xforms:repeat.  Need to use the
00211       //   service to do this work so that we don't have dependencies in
00212       //   transformiix on XForms.
00213       nsCOMPtr<nsIXFormsUtilityService>xformsService =
00214             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00215       NS_ENSURE_SUCCESS(rv, rv);
00216 
00217       PRInt32 index = 0;
00218       double res = Double::NaN;
00219       rv = xformsService->GetRepeatIndexById(mNode, indexId, &index);
00220       NS_ENSURE_SUCCESS(rv, rv);
00221 
00222       if (index >= 0) {
00223         // repeat's index is 1-based.  If it is 0, then that is still ok since
00224         // repeat's index can be 0 if uninitialized or if the nodeset that it
00225         // is bound to is empty (either initially or due to delete remove all
00226         // of the instance nodes).  If index == -1, then repeatEle isn't an
00227         // XForms repeat element, so we need to return NaN per spec.
00228         res = index;
00229       }
00230 
00231       return aContext->recycler()->getNumberResult(res, aResult);
00232 
00233     }
00234     case INSTANCE:
00235     {
00236       nsresult rv;
00237       if (!requireParams(1, 1, aContext))
00238         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00239    
00240       nsRefPtr<txNodeSet> resultSet;
00241       rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
00242       NS_ENSURE_SUCCESS(rv, rv);
00243    
00244       nsAutoString instanceId;
00245       evaluateToString((Expr*)iter.next(), aContext, instanceId);
00246    
00247       // here document is the XForms document
00248       nsCOMPtr<nsIDOMDocument> document;
00249       rv = mNode->GetOwnerDocument(getter_AddRefs(document));
00250       NS_ENSURE_SUCCESS(rv, rv);
00251       NS_ENSURE_TRUE(document, NS_ERROR_NULL_POINTER);
00252  
00253       nsCOMPtr<nsIDOMElement> instEle;
00254       rv = document->GetElementById(instanceId, getter_AddRefs(instEle));
00255  
00256       PRBool foundInstance = PR_FALSE;
00257       nsAutoString localname, namespaceURI;
00258       if (instEle) {
00259         instEle->GetLocalName(localname);
00260         instEle->GetNamespaceURI(namespaceURI);
00261         if (localname.EqualsLiteral("instance") && 
00262             namespaceURI.EqualsLiteral(NS_NAMESPACE_XFORMS)) {
00263           foundInstance = PR_TRUE;
00264         }
00265       }
00266  
00267       if (!foundInstance) {
00268         // We didn't find an instance element with the given id.  Return the
00269         //   empty result set.
00270         *aResult = resultSet;
00271         NS_ADDREF(*aResult);
00272     
00273         return NS_OK;
00274       }
00275  
00276       // Make sure that this element is contained in the same
00277       //   model as the context node of the expression as per
00278       //   the XForms 1.0 spec.
00279  
00280       // first step is to get the contextNode passed in to
00281       //   the evaluation
00282  
00283       nsCOMPtr<nsIDOMNode> xfContextNode;
00284       rv = txXPathNativeNode::getNode(aContext->getContextNode(), 
00285                                       getter_AddRefs(xfContextNode)); 
00286       NS_ENSURE_SUCCESS(rv, rv);
00287  
00288       // now see if the node we found (instEle) and the 
00289       //   context node for the evaluation (xfContextNode) link
00290       //   back to the same model. 
00291       nsCOMPtr<nsIXFormsUtilityService>xformsService = 
00292             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00293       NS_ENSURE_SUCCESS(rv, rv);
00294  
00295       nsCOMPtr<nsIDOMNode> instNode, modelInstance;
00296       instNode = do_QueryInterface(instEle);
00297       rv = xformsService->GetModelFromNode(instNode, 
00298                                            getter_AddRefs(modelInstance)); 
00299                                  
00300       NS_ENSURE_SUCCESS(rv, rv);
00301  
00302       PRBool modelContainsNode = PR_FALSE;
00303       rv = xformsService->IsNodeAssocWithModel(xfContextNode, 
00304                                                modelInstance, 
00305                                                &modelContainsNode);
00306       NS_ENSURE_SUCCESS(rv, rv);
00307  
00308       if (modelContainsNode) {
00309         // ok, we've found an instance node with the proper id
00310         //   that fulfills the requirement of being from the
00311         //   same model as the context node.  Now we need to
00312         //   return a 'node-set containing just the root
00313         //   element node of the referenced instance data'.
00314         //   Wonderful.
00315  
00316         nsCOMPtr<nsIDOMNode> instanceRoot;
00317         rv = xformsService->GetInstanceDocumentRoot(
00318                               instanceId,
00319                               modelInstance,
00320                               getter_AddRefs(instanceRoot));
00321         NS_ENSURE_SUCCESS(rv, rv);
00322         if (instanceRoot) {
00323           nsAutoPtr<txXPathNode> txNode(txXPathNativeNode::createXPathNode(instanceRoot));
00324           if (txNode) {
00325             resultSet->add(*txNode);
00326           }
00327         }
00328       }
00329  
00330  
00331         // XXX where we need to do the work
00332        // if (walker.moveToElementById(instanceId)) {
00333        //     resultSet->add(walker.getCurrentPosition());
00334        // }
00335    
00336       *aResult = resultSet;
00337       NS_ADDREF(*aResult);
00338    
00339       return NS_OK;
00340     }
00341     case MAX:
00342     {
00343       if (!requireParams(1, 1, aContext))
00344         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00345 
00346       nsRefPtr<txNodeSet> nodes;
00347       nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
00348                                       getter_AddRefs(nodes));
00349       NS_ENSURE_SUCCESS(rv, rv);
00350    
00351       double res = Double::NaN;
00352       PRInt32 i;
00353       for (i = 0; i < nodes->size(); ++i) {
00354         double test;
00355         nsAutoString resultStr;
00356         txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
00357         test = Double::toDouble(resultStr);
00358         if (Double::isNaN(test)) {
00359           res = Double::NaN;
00360           break;
00361         }
00362         if (test > res || i == 0) {
00363           res = test;
00364         }
00365       }
00366    
00367       return aContext->recycler()->getNumberResult(res, aResult);
00368     }
00369     case MIN:
00370     {
00371       if (!requireParams(1, 1, aContext))
00372         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00373 
00374       nsRefPtr<txNodeSet> nodes;
00375       nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
00376                                       getter_AddRefs(nodes));
00377       NS_ENSURE_SUCCESS(rv, rv);
00378    
00379       double res = Double::NaN;
00380       PRInt32 i;
00381       for (i = 0; i < nodes->size(); ++i) {
00382         double test;
00383         nsAutoString resultStr;
00384         txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
00385         test = Double::toDouble(resultStr);
00386         if (Double::isNaN(test)) {
00387           res = Double::NaN;
00388           break;
00389         }
00390         if ((test < res) || (i==0)) {
00391           res = test;
00392         }
00393       }
00394    
00395       return aContext->recycler()->getNumberResult(res, aResult);
00396     }
00397     case MONTHS:
00398     {
00399       if (!requireParams(1, 1, aContext))
00400         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00401    
00402       nsAutoString duration;
00403       evaluateToString((Expr*)iter.next(), aContext, duration);
00404    
00405       nsCOMPtr<nsIXFormsUtilityService>xformsService = 
00406             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00407       NS_ENSURE_SUCCESS(rv, rv);
00408 
00409       PRInt32 result = 0;
00410       double res = Double::NaN;
00411       nsresult rv = xformsService->GetMonths(duration, &result);
00412       if (NS_SUCCEEDED(rv)) {
00413         res = result;
00414       } 
00415       else if (rv != NS_ERROR_ILLEGAL_VALUE) {
00416         // if we failed for a reason other than the parameter value, pass that 
00417         // up the chain
00418         return rv;
00419       }
00420 
00421       return aContext->recycler()->getNumberResult(res, aResult);
00422     }
00423     case NOW:
00424     {
00425       if (!requireParams(0, 0, aContext))
00426         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00427 
00428       nsCOMPtr<nsIXFormsUtilityService>xformsService =
00429             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00430       NS_ENSURE_SUCCESS(rv, rv);
00431 
00432       nsAutoString res;
00433       xformsService->GetTime(res, PR_TRUE);
00434    
00435       return aContext->recycler()->getStringResult(res, aResult);
00436     }
00437     case LOCALDATETIME:
00438     {
00439       if (!requireParams(0, 0, aContext))
00440         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00441 
00442       nsCOMPtr<nsIXFormsUtilityService>xformsService =
00443             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00444       NS_ENSURE_SUCCESS(rv, rv);
00445 
00446       nsAutoString res;
00447       xformsService->GetTime(res, PR_FALSE);
00448    
00449       return aContext->recycler()->getStringResult(res, aResult);
00450     }
00451     case LOCALDATE:
00452     {
00453       if (!requireParams(0, 0, aContext))
00454         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00455 
00456       nsCOMPtr<nsIXFormsUtilityService>xformsService =
00457             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00458       NS_ENSURE_SUCCESS(rv, rv);
00459 
00460       nsAutoString time, res;
00461       xformsService->GetTime(time, PR_FALSE);
00462 
00463       // since we know that the returned string will be in the format of
00464       // yyyy-mm-ddThh:mm:ss.ssszzzz, we just need to grab the first 10
00465       // characters to represent the date and then strip off the time zone
00466       // information from the end and append it to the string to get our answer
00467       res = Substring(time, 0, 10);
00468       PRInt32 timeSeparator = time.FindChar(PRUnichar('T'));
00469       if (timeSeparator == kNotFound) {
00470         // though this should probably never happen, if this is the case we
00471         // certainly don't have to worry about timezones.  Just return.
00472         return NS_ERROR_UNEXPECTED;
00473       }
00474   
00475       // Time zone information can be of the format '-hh:ss', '+hh:ss', or 'Z'
00476       // might be no time zone information at all.
00477       nsAutoString hms(Substring(time, timeSeparator+1, time.Length()));
00478       PRInt32 timeZoneSeparator = hms.FindChar(PRUnichar('-'));
00479       if (timeZoneSeparator == kNotFound) {
00480         timeZoneSeparator = hms.FindChar(PRUnichar('+'));
00481         if (timeZoneSeparator == kNotFound) {
00482           timeZoneSeparator = hms.FindChar(PRUnichar('Z'));
00483           if (timeZoneSeparator == kNotFound) {
00484             // no time zone information available
00485             return NS_ERROR_UNEXPECTED;
00486           }
00487         }
00488       }
00489   
00490       res.Append(Substring(hms, timeZoneSeparator, hms.Length()));
00491       return aContext->recycler()->getStringResult(res, aResult);
00492     }
00493     case PROPERTY:
00494     {
00495       if (!requireParams(1, 1, aContext))
00496         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00497    
00498       nsAutoString property;
00499       evaluateToString((Expr*)iter.next(), aContext, property);
00500  
00501       // This function can handle "version" and "conformance-level"
00502       //   which is all that the XForms 1.0 spec is worried about
00503       if (property.Equals(NS_LITERAL_STRING("version")))
00504         property.Assign(NS_LITERAL_STRING("1.0"));
00505       else if (property.Equals(NS_LITERAL_STRING("conformance-level")))
00506         property.Assign(NS_LITERAL_STRING("basic"));
00507    
00508       return aContext->recycler()->getStringResult(property, aResult);
00509     }
00510     case SECONDS:
00511     {
00512       if (!requireParams(1, 1, aContext))
00513           return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00514    
00515       nsAutoString duration;
00516       evaluateToString((Expr*)iter.next(), aContext, duration);
00517    
00518       nsCOMPtr<nsIXFormsUtilityService>xformsService = 
00519             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00520       NS_ENSURE_SUCCESS(rv, rv);
00521 
00522       double res;
00523       nsresult rv = xformsService->GetSeconds(duration, &res);
00524       if (NS_FAILED(rv)) {
00525         if (rv != NS_ERROR_ILLEGAL_VALUE) {
00526           // if we failed for a reason other than the parameter value, pass that 
00527           // up the chain
00528           return rv;
00529         }
00530         res = Double::NaN;
00531       }
00532 
00533       return aContext->recycler()->getNumberResult(res, aResult);
00534     }
00535     case SECONDSFROMDATETIME:
00536     {
00537       if (!requireParams(1, 1, aContext))
00538         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00539    
00540       nsAutoString dateTime;
00541       evaluateToString((Expr*)iter.next(), aContext, dateTime);
00542    
00543       nsCOMPtr<nsIXFormsUtilityService>xformsService = 
00544             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00545       NS_ENSURE_SUCCESS(rv, rv);
00546 
00547       double res;
00548       nsresult rv = xformsService->GetSecondsFromDateTime(dateTime, &res);
00549       if (NS_FAILED(rv)) {
00550         if (rv != NS_ERROR_ILLEGAL_VALUE) {
00551           // if we failed for a reason other than the parameter value, pass that 
00552           // up the chain
00553           return rv;
00554         }
00555         res = Double::NaN;
00556       }
00557 
00558       return aContext->recycler()->getNumberResult(res, aResult);
00559     }
00560     case CURRENT:
00561     {
00562       if (!requireParams(0, 0, aContext))
00563         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00564    
00565       nsRefPtr<txNodeSet> resultSet;
00566       rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
00567       NS_ENSURE_SUCCESS(rv, rv);
00568 
00569       // mNode will be the original context node that was used when the
00570       // expression was built.
00571       if (mNode) {
00572         nsAutoPtr<txXPathNode> txNode(txXPathNativeNode::createXPathNode(mNode));
00573         if (txNode) {
00574           resultSet->add(*txNode);
00575         }
00576       }
00577 
00578       *aResult = resultSet;
00579       NS_ADDREF(*aResult);
00580 
00581       return NS_OK;
00582     }
00583     case EVENT:
00584     {
00585       // The Event function returns a nodeset of context info associated with
00586       // an event.
00587       nsresult rv;
00588       if (!requireParams(1, 1, aContext))
00589         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00590 
00591       nsRefPtr<txNodeSet> resultSet;
00592       rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
00593       NS_ENSURE_SUCCESS(rv, rv);
00594 
00595       // Get the name of the context info property.
00596       nsAutoString contextName;
00597       evaluateToString((Expr*)iter.next(), aContext, contextName);
00598 
00599       nsCOMPtr<nsIXFormsUtilityService>xformsService =
00600             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00601       NS_ENSURE_SUCCESS(rv, rv);
00602 
00603       // mNode is the node that contained the Event XPath expression.
00604       nsCOMArray<nsIDOMNode> contextInfo;
00605       rv = xformsService->GetEventContextInfo(contextName, mNode, &contextInfo);
00606       NS_ENSURE_SUCCESS(rv, rv);
00607 
00608       // Add each of the context info nodes to the resultSet.
00609       PRInt32 i;
00610       for (i = 0; i < contextInfo.Count(); ++i) {
00611         nsAutoPtr<txXPathNode> txNode(txXPathNativeNode::createXPathNode(contextInfo[i]));
00612         if (txNode) {
00613           resultSet->add(*txNode);
00614         }
00615       }
00616 
00617       *aResult = resultSet;
00618       NS_ADDREF(*aResult);
00619 
00620       return NS_OK;
00621     }
00622     case POWER:
00623     {
00624       if (!requireParams(2, 2, aContext))
00625         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00626 
00627       double result = 0;
00628       double base = evaluateToNumber((Expr*)iter.next(), aContext);
00629       double exponent = evaluateToNumber((Expr*)iter.next(), aContext);
00630 
00631       // If base is negative and exponent is not an integral value, or if base
00632       // is zero and exponent is negative, a domain error occurs, setting the
00633       // global variable errno to the value EDOM.
00634       // If the result is too large (ERANGE), we consider the result to be kNaN.
00635       result = pow(base, exponent);
00636       if (errno == EDOM || errno == ERANGE) {
00637         result = Double::NaN;
00638       }
00639 
00640       return aContext->recycler()->getNumberResult(result, aResult);
00641     }
00642     case RANDOM:
00643     {
00644       if (!requireParams(0, 1, aContext))
00645         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00646 
00647       PRBool useSeed = PR_FALSE;
00648       Expr *expr = (Expr*)iter.next();
00649       if (expr) {
00650         useSeed = evaluateToBoolean(expr, aContext);
00651       }
00652 
00653       if (useSeed) {
00654         // initialize random seed.
00655         PRUint32 seed = 0;
00656         PRSize rSize = PR_GetRandomNoise(&seed, sizeof(seed));
00657         if (rSize) {
00658           srand (seed);
00659         }
00660       }
00661       double result = (rand() / ((double)RAND_MAX + 1.0));
00662 
00663       return aContext->recycler()->getNumberResult(result, aResult);
00664     }
00665     case COMPARE:
00666     {
00667       if (!requireParams(2, 2, aContext))
00668         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00669 
00670       nsAutoString string1, string2;
00671       evaluateToString((Expr*)iter.next(), aContext, string1);
00672       evaluateToString((Expr*)iter.next(), aContext, string2);
00673 
00674       // Using strcmp because Compare is not a member of nsAutoString.
00675       double result = 0;
00676       result = strcmp(NS_ConvertUTF16toUTF8(string1).get(),
00677                       NS_ConvertUTF16toUTF8(string2).get());
00678 
00679       return aContext->recycler()->getNumberResult(result, aResult);
00680     }
00681     case CONTEXT:
00682     {
00683       if (!requireParams(0, 0, aContext))
00684         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00685 
00686       nsRefPtr<txNodeSet> resultSet;
00687       rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
00688       NS_ENSURE_SUCCESS(rv, rv);
00689 
00690       nsCOMPtr<nsIXFormsUtilityService> xformsService =
00691             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00692       NS_ENSURE_SUCCESS(rv, rv);
00693 
00694       // mNode will be the node that contained the context() function.
00695       nsCOMPtr<nsIDOMNode> contextNode;
00696       rv = xformsService->Context(mNode, getter_AddRefs(contextNode));
00697 
00698       if (contextNode) {
00699         nsAutoPtr<txXPathNode> txNode(txXPathNativeNode::createXPathNode(contextNode));
00700         if (txNode) {
00701           resultSet->add(*txNode);
00702         }
00703       }
00704 
00705       *aResult = resultSet;
00706       NS_ADDREF(*aResult);
00707 
00708       return NS_OK;
00709     }
00710     case DAYSTODATE:
00711     {
00712       if (!requireParams(1, 1, aContext))
00713         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00714 
00715       double days = evaluateToNumber((Expr*)iter.next(), aContext);
00716 
00717       nsAutoString date;
00718       if (!Double::isNaN(days)) {
00719         // Round total number of days to the nearest whole number.
00720         PRTime t_days;
00721         LL_I2L(t_days, floor(days+0.5));
00722 
00723         PRTime t_secs, t_secs_per_day, t_usec, usec_per_sec;
00724         // Calculate total number of seconds in aDays.
00725         LL_I2L(t_secs_per_day, 86400UL);
00726         LL_MUL(t_secs, t_days, t_secs_per_day);
00727         // Convert total seconds to usecs.
00728         LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
00729         LL_MUL(t_usec, t_secs, usec_per_sec);
00730 
00731         // Convert the time to xsd:date format.
00732         PRExplodedTime et;
00733         PR_ExplodeTime(t_usec, PR_GMTParameters, &et);
00734         char ctime[60];
00735         PR_FormatTime(ctime, sizeof(ctime), "%Y-%m-%d", &et);
00736         date.AppendASCII(ctime);
00737       }
00738 
00739       return aContext->recycler()->getStringResult(date, aResult);
00740 
00741       return NS_OK;
00742     }
00743     case SECONDSTODATETIME:
00744     {
00745       if (!requireParams(1, 1, aContext))
00746         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00747 
00748       double seconds = evaluateToNumber((Expr*)iter.next(), aContext);
00749 
00750       nsAutoString dateTime;
00751       if (!Double::isNaN(seconds)) {
00752         // Round total number of seconds to the nearest whole number.
00753         PRTime t_secs;
00754         LL_I2L(t_secs, floor(seconds+0.5));
00755 
00756         // Convert total seconds to usecs.
00757         PRTime t_usec, usec_per_sec;
00758         LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
00759         LL_MUL(t_usec, t_secs, usec_per_sec);
00760 
00761         // Convert the time to xsd:dateTime format.
00762         PRExplodedTime et;
00763         PR_ExplodeTime(t_usec, PR_GMTParameters, &et);
00764         char ctime[60];
00765         PR_FormatTime(ctime, sizeof(ctime), "%Y-%m-%dT%H:%M:%SZ", &et);
00766         dateTime.AppendASCII(ctime);
00767       }
00768 
00769       return aContext->recycler()->getStringResult(dateTime, aResult);
00770     }
00771     case ISCARDNUMBER:
00772     {
00773       if (!requireParams(1, 1, aContext))
00774         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00775 
00776       nsAutoString number;
00777       evaluateToString((Expr*)iter.next(), aContext, number);
00778 
00779       nsCOMPtr<nsIXFormsUtilityService>xformsService =
00780             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00781       NS_ENSURE_SUCCESS(rv, rv);
00782 
00783       PRBool result;
00784       rv = xformsService->IsCardNumber(number, &result);
00785       NS_ENSURE_SUCCESS(rv, rv);
00786 
00787       aContext->recycler()->getBoolResult(result, aResult);
00788 
00789       return NS_OK;
00790     }
00791     case DIGEST:
00792     {
00793       nsresult rv;
00794       if (!requireParams(2, 3, aContext))
00795         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00796 
00797       nsAutoString data, algorithm, encoding;
00798       evaluateToString((Expr*)iter.next(), aContext, data);
00799       evaluateToString((Expr*)iter.next(), aContext, algorithm);
00800       evaluateToString((Expr*)iter.next(), aContext, encoding);
00801 
00802       nsCOMPtr<nsIXFormsUtilityService>xformsService =
00803             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00804       NS_ENSURE_SUCCESS(rv, rv);
00805 
00806       // mNode is the node that contained the Event XPath expression.
00807       nsAutoString result;
00808       rv = xformsService->Digest(data, algorithm, encoding, mNode, result);
00809       if (NS_FAILED(rv)) {
00810         return rv;
00811       }
00812 
00813       return aContext->recycler()->getStringResult(result, aResult);
00814     }
00815     case ADJUSTDATETIMETOTIMEZONE:
00816     {
00817       nsresult rv;
00818       if (!requireParams(1, 1, aContext))
00819         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00820 
00821       nsAutoString dateTime;
00822       evaluateToString((Expr*)iter.next(), aContext, dateTime);
00823 
00824       nsCOMPtr<nsIXFormsUtilityService>xformsService =
00825             do_GetService("@mozilla.org/xforms-utility-service;1", &rv);
00826       NS_ENSURE_SUCCESS(rv, rv);
00827 
00828       nsAutoString result;
00829       rv = xformsService->AdjustDateTimeToTimezone(dateTime, result);
00830       if (NS_FAILED(rv)) {
00831         return rv;
00832       }
00833 
00834       return aContext->recycler()->getStringResult(result, aResult);
00835     }
00836   } /* switch() */
00837 
00838   aContext->receiveError(NS_LITERAL_STRING("Internal error"),
00839                          NS_ERROR_UNEXPECTED);
00840   return NS_ERROR_UNEXPECTED;
00841 }
00842 
00843   #ifdef TX_TO_STRING
00844 nsresult
00845 XFormsFunctionCall::getNameAtom(nsIAtom** aAtom)
00846 {
00847   switch (mType) {
00848     case AVG:
00849     {
00850       *aAtom = txXPathAtoms::avg;
00851       break;
00852     }
00853     case BOOLEANFROMSTRING:
00854     {
00855       *aAtom = txXPathAtoms::booleanFromString;
00856       break;
00857     }
00858     case COUNTNONEMPTY:
00859     {
00860       *aAtom = txXPathAtoms::countNonEmpty;
00861       break;
00862     }
00863     case DAYSFROMDATE:
00864     {
00865       *aAtom = txXPathAtoms::daysFromDate;
00866       break;
00867     }
00868     case IF:
00869     {
00870       *aAtom = txXPathAtoms::ifFunc;
00871       break;
00872     }
00873     case INDEX:
00874     {
00875       *aAtom = txXPathAtoms::index;
00876       break;
00877     }
00878     case INSTANCE:
00879     {
00880       *aAtom = txXPathAtoms::instance;
00881       break;
00882     }
00883     case MAX:
00884     {
00885       *aAtom = txXPathAtoms::max;
00886       break;
00887     }
00888     case MIN:
00889     {
00890       *aAtom = txXPathAtoms::min;
00891       break;
00892     }
00893     case MONTHS:
00894     {
00895       *aAtom = txXPathAtoms::months;
00896       break;
00897     }
00898     case NOW:
00899     {
00900       *aAtom = txXPathAtoms::now;
00901       break;
00902     }
00903     case LOCALDATETIME:
00904     {
00905       *aAtom = txXPathAtoms::localDateTime;
00906       break;
00907     }
00908     case LOCALDATE:
00909     {
00910       *aAtom = txXPathAtoms::localDate;
00911       break;
00912     }
00913     case PROPERTY:
00914     {
00915       *aAtom = txXPathAtoms::property;
00916       break;
00917     }
00918     case SECONDS:
00919     {
00920       *aAtom = txXPathAtoms::seconds;
00921       break;
00922     }
00923     case SECONDSFROMDATETIME:
00924     {
00925       *aAtom = txXPathAtoms::secondsFromDateTime;
00926       break;
00927     }
00928     case CURRENT:
00929     {
00930       *aAtom = txXPathAtoms::current;
00931       break;
00932     }
00933     case EVENT:
00934     {
00935       *aAtom = txXPathAtoms::event;
00936       break;
00937     }
00938     case POWER:
00939     {
00940       *aAtom = txXPathAtoms::power;
00941       break;
00942     }
00943     case RANDOM:
00944     {
00945       *aAtom = txXPathAtoms::random;
00946       break;
00947     }
00948     case COMPARE:
00949     {
00950       *aAtom = txXPathAtoms::compare;
00951       break;
00952     }
00953     case CONTEXT:
00954     {
00955       *aAtom = txXPathAtoms::context;
00956       break;
00957     }
00958     case DAYSTODATE:
00959     {
00960       *aAtom = txXPathAtoms::daysToDate;
00961       break;
00962     }
00963     case SECONDSTODATETIME:
00964     {
00965       *aAtom = txXPathAtoms::secondsToDateTime;
00966       break;
00967     }
00968     case ISCARDNUMBER:
00969     {
00970       *aAtom = txXPathAtoms::isCardNumber;
00971       break;
00972     }
00973     case DIGEST:
00974     {
00975       *aAtom = txXPathAtoms::digest;
00976       break;
00977     }
00978     case ADJUSTDATETIMETOTIMEZONE:
00979     {
00980       *aAtom = txXPathAtoms::adjustDateTimeToTimezone;
00981       break;
00982     }
00983     default:
00984     {
00985       *aAtom = 0;
00986       return NS_ERROR_FAILURE;
00987     }
00988   }
00989   NS_ADDREF(*aAtom);
00990   return NS_OK;
00991 }
00992 #endif