Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AddEval.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AddEval.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/eval/AddEval.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,70 @@ +/* + * Created on May 8, 2005 + * + */ +package org.apache.poi.hssf.record.formula.eval; + +import java.lang.reflect.Constructor; + +import org.apache.poi.hssf.record.formula.AddPtg; +import org.apache.poi.hssf.record.formula.Ptg; + +/** + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * + */ +public class AddEval implements OperationEval { + + private AddPtg delegate; + + public AddEval(Ptg ptg) { + delegate = (AddPtg) ptg; + } + + + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.eval.OperationEval#evaluate(org.apache.poi.hssf.record.formula.eval.Eval[]) + */ + public Eval evaluate(Eval[] operands) { + double d = 0; + Eval retval = null; + for (int i=0, iSize=getNumberOfOperands(); i + * Function spec: + * 1. numargs= 1-3 + * 2. args= 1: number; 2: decimal places; 3: show thousands separator? + * + */ +public class Fixed extends DefaultFunctionImpl { + + private static final boolean DEFAULT_SHOW_THOUSANDS_SEP = true; + private static final int DEFAULT_NUM_DIGITS_AFTER_DECIMALS = 2; + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + double d; + boolean showThousandsSep = DEFAULT_SHOW_THOUSANDS_SEP; + int numdecimals=DEFAULT_NUM_DIGITS_AFTER_DECIMALS; + + switch (operands.length) { + case 3: + if (operands[2] instanceof NumericValueEval) { + NumericValueEval np = (NumericValueEval) operands[2]; + showThousandsSep = np.getNumberValue() != 0; + } + else { + showThousandsSep = false; + } + case 2: + if (operands[1] instanceof NumericValueEval) { + NumericValueEval np = (NumericValueEval) operands[1]; + numdecimals = (int) np.getNumberValue(); + } + else { + numdecimals = 0; + } + default: // 1 operand + if (operands[0] instanceof NumericValueEval) { + NumericValueEval np = (NumericValueEval) operands[0]; + d = np.getNumberValue(); + } + else { + d = 0; + } + } + + // String str = formatDecimal(d, numdecimals, showThousandsSep); + // return new StringPtg(str); + // TODO: this is a little tricky function to implement: + // because while display value is a fixed format string, + // the type is treated as numeric when used in formulas. + // For now, the returned type is kept "NumberEval" + // since it will cause it to work better with other + // formulas. + // MoreImportantly, OpenOffice and Excel differ in their + // implementation of FIXED, Oo treats FIXED eval as + // String, Excel treats it as Number - This class + // treats it as a number but/hence does not do the + // formatting that FIXED should: In programs, this + // impl should be more useful. + // To switch to strictly Oo implementation, uncomment the + // 2 lines above this_TODO and remove the lines below + // this_TODO. + + return new NumberEval(d); + } + + /** + * return string representation of double with specified formatting options + * @param d + * @param numdecimals + * @param showT + * @return + */ + static final String formatDecimal(double d, int numdecimals, boolean showT) { + StringBuffer sb = new StringBuffer(50); // 50 => optimze for speed for common values + long integral = (long) d; + double fraction = d-integral; + + if (showT) { + String sintegral = String.valueOf(integral); + for (int i=sintegral.length()-1, j=1; i>=0; i--, j++) { + char c = sintegral.charAt(i); + sb.append(c); + if (j%3==0 && i!=0) sb.append(','); + } + sb.reverse(); + } + else { + sb.append(integral); + } + sb.append(ensureLength(fraction, numdecimals)); + return sb.toString(); + } + + // TODO: optimize this function + /** + * returns a truncated or padded String representation of + * double fraction. double fraction MUST be >0 && <1. + */ + static final String ensureLength(double fraction, int numdecimals) { + StringBuffer sb = new StringBuffer(); + if (numdecimals != 0) { + int ifraction = (int) (fraction * Math.pow(10, numdecimals)); + String sfraction = String.valueOf(ifraction); + + sb.append('.').append(ifraction); + for (int i=numdecimals-sfraction.length(); i>0; i--) { + sb.append('0'); + } + } + return sb.toString(); + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Function.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Function.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Function.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,18 @@ +/* + * Created on May 9, 2005 + * + * TODO To change the template for this generated file go to + * Window - Preferences - Java - Code Style - Code Templates + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.Eval; + +/** + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * + */ +public interface Function { + + public Eval evaluate(Eval[] operands); +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Int.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Int.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Int.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,52 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class Int extends DefaultFunctionImpl { + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + double d = 0; + ValueEval retval = null; + if (operands.length == 1) { + if (operands[0] instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) operands[0]; + d = ne.getNumberValue(); + } + else if (operands[0] instanceof RefEval) { + + } + else if (operands[0] instanceof StringEval) { + retval = ErrorEval.ERROR_502; + } + } + else if (operands.length > 1) { + retval = ErrorEval.ERROR_508; + } + else { + retval = ErrorEval.ERROR_511; + } + if (retval == null) { + retval = new NumberEval(d); + } + + return retval; + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsError.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsError.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsError.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,26 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.BoolEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class IsError extends DefaultFunctionImpl { + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + boolean b = (operands[0] instanceof ErrorEval) || (operands[0] instanceof AreaEval); + return new BoolEval(b); + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsNa.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsNa.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/IsNa.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,25 @@ +/* + * Created on May 6, 2005 + * + * TODO To change the template for this generated file go to + * Window - Preferences - Java - Code Style - Code Templates + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.Eval; + +/** + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * + * Window - Preferences - Java - Code Style - Code Templates + */ +public class IsNa extends DefaultFunctionImpl { + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + return super.evaluate(operands); + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ln.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ln.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Ln.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,61 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class Ln extends DefaultFunctionImpl { + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + double d = 0; + ValueEval retval = null; + switch (operands.length) { + case 1: + if (operands[0] instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) operands[0]; + d = Math.log(ne.getNumberValue()); + } + else if (operands[0] instanceof RefEval) { + RefEval re = (RefEval) operands[0]; + ValueEval ve = re.getInnerValueEval(); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) ve; + d = Math.log(ne.getNumberValue()); + } + } + else if (operands[0] instanceof AreaEval) { + retval = ErrorEval.INVALID_VALUE; + } + else { + retval = ErrorEval.ERROR_502; + } + break; + case 0: + retval = ErrorEval.ERROR_502; + break; + default: + retval = ErrorEval.ERROR_508; + } + if (retval == null) { + retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.ERROR_503 : new NumberEval(d); + } + + return retval; + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log10.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log10.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Log10.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,63 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class Log10 extends DefaultFunctionImpl { + private static final double LOG_10_TO_BASE_e = Math.log(10); + + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + double d = 0; + ValueEval retval = null; + switch (operands.length) { + case 1: + if (operands[0] instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) operands[0]; + d = Math.log(ne.getNumberValue()); + } + else if (operands[0] instanceof RefEval) { + RefEval re = (RefEval) operands[0]; + ValueEval ve = re.getInnerValueEval(); + if (ve instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) operands[0]; + d = Math.log(ne.getNumberValue()); + } + } + else if (operands[0] instanceof AreaEval) { + retval = ErrorEval.INVALID_VALUE; + } + else { + retval = ErrorEval.ERROR_502; + } + break; + case 0: + retval = ErrorEval.ERROR_502; + break; + default: + retval = ErrorEval.ERROR_508; + } + if (retval != null) { + retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.ERROR_503 : new NumberEval(d/LOG_10_TO_BASE_e); + } + + return retval; + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Max.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Max.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Max.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,54 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class Max extends DefaultFunctionImpl { + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + double d = 0; + for (int i=0, iSize=operands.length; i 2) { + retval = ErrorEval.ERROR_504; + } + if (retval == null) { + double power = Math.pow(10, accuracy); + d *= power; + d = Math.round(d); + retval = new NumberEval(d/power); + } + return retval; + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Row.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Row.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Row.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,33 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class Row extends DefaultFunctionImpl { + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + Eval retval = null; + if (operands[0] instanceof RefEval) { + RefEval rp = (RefEval) operands[0]; + retval = new NumberEval(rp.getRow()+1); + } + else { + retval = ErrorEval.ERROR_504; + } + return retval; + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sign.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sign.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sign.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,44 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class Sign extends DefaultFunctionImpl { + + private static final NumberEval NEG_SIGN_EVAL = new NumberEval(-1); + private static final NumberEval POS_SIGN_EVAL = new NumberEval(1); + private static final NumberEval ZERO_SIGN_EVAL = new NumberEval(0); + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + double d = 0; + ValueEval retval = null; + if (operands[0] instanceof NumericValueEval) { + NumericValueEval nve = (NumericValueEval) operands[0]; + d = nve.getNumberValue(); + } + if (d == 0) { + retval = ZERO_SIGN_EVAL; + } + else if (d < 0) { + retval = NEG_SIGN_EVAL; + } + else if (d > 0) { + retval = POS_SIGN_EVAL; + } + return retval; + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sin.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sin.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sin.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,55 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class Sin extends DefaultFunctionImpl { + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + ValueEval retval = null; + double d = 0; + if (operands.length == 1) { + if (operands[0] instanceof NumericValueEval) { + NumericValueEval np = (NumericValueEval) operands[0]; + d = Math.sin(np.getNumberValue()); + } + else if (operands[0] instanceof RefEval) { + RefEval re = (RefEval) operands[0]; + ValueEval ve = re.getInnerValueEval(); + if (ve!=null && ve instanceof NumericValueEval) { + NumericValueEval np = (NumericValueEval) ve; + d = Math.sin(np.getNumberValue()); + } + } + else if (operands[0] instanceof AreaEval) { + retval = ErrorEval.INVALID_VALUE; + } + else { + retval = ErrorEval.ERROR_502; + } + } + else { + retval = ErrorEval.ERROR_508; + } + if (retval == null) + retval = new NumberEval(d); + return retval; + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sqrt.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sqrt.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Sqrt.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,56 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class Sqrt extends DefaultFunctionImpl { + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + ValueEval retval = null; + double d = 0; + if (operands.length == 1) { + if (operands[0] instanceof NumericValueEval) { + NumericValueEval np = (NumericValueEval) operands[0]; + d = Math.sqrt(np.getNumberValue()); + } + else if (operands[0] instanceof RefEval) { + RefEval re = (RefEval) operands[0]; + ValueEval ve = re.getInnerValueEval(); + if (ve!=null && ve instanceof NumericValueEval) { + NumericValueEval np = (NumericValueEval) ve; + d = Math.sqrt(np.getNumberValue()); + } + } + else if (operands[0] instanceof AreaEval) { + retval = ErrorEval.INVALID_VALUE; + } + else { + retval = ErrorEval.ERROR_502; + } + } + else { + retval = ErrorEval.ERROR_508; + } + if (retval != null) { + retval = (Double.isNaN(d)) ? (ValueEval) ErrorEval.ERROR_502 : new NumberEval(d); + } + return retval; + } + +} Index: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Stdev.java =================================================================== RCS file: src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Stdev.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Stdev.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,79 @@ +/* + * Created on May 6, 2005 + * + */ +package org.apache.poi.hssf.record.formula.functions; + +import org.apache.poi.hssf.record.formula.eval.Eval; + +/** + * @author amolweb < amolweb at ya hoo dot com > + * + */ +public class Stdev extends DefaultFunctionImpl { + + /* (non-Javadoc) + * @see org.apache.poi.hssf.record.formula.functions.Function#evaluate(org.apache.poi.hssf.record.formula.Ptg[]) + */ + public Eval evaluate(Eval[] operands) { + return super.evaluate(operands); +// double mean = 0; +// int count = 0; +// double numerator = 0; +// +// for (int i=0, iSize=operands.length; i"); + for (int i=0, iSize=ptgs.length; i"); + System.out.println(ptgs[i]); + if (ptgs[i] instanceof OperationPtg) { + System.out.println("numoperands: " + ((OperationPtg) ptgs[i]).getNumberOfOperands()); + } + System.out.println(""); + } + } + + /** + * returns the string value resulting from teh evaluation of the formula + * @param formula + * @param sheet + * @param workbook + * @return + */ + public static String evaluateToString(String formula, HSSFSheet sheet, HSSFWorkbook workbook) { + String retval = null; + Eval value = evaluate(formula, sheet, workbook); + if (value instanceof NumericValueEval) { + NumericValueEval ne = (NumericValueEval) value; + retval = String.valueOf(ne.getNumberValue()); + } + else if (value instanceof StringValueEval) { + StringValueEval se = (StringValueEval) value; + retval = se.getStringValue(); + } + else { + retval = value.getClass().getName(); + } + return retval; + } + + /** + * evaluates a formula!!! :) + * @param formula + * @param sheet + * @param workbook + * @return + */ + private static Eval evaluate(String formula, HSSFSheet sheet, HSSFWorkbook workbook) { + FormulaParser parser = new FormulaParser(formula, workbook.getWorkbook()); + parser.parse(); + Ptg[] ptgs = parser.getRPNPtg(); + // -- parsing over -- + + Stack stack = new Stack(); + for (int i=0, iSize=ptgs.length; i=0; j--) { // storing the ops in reverse order since they are popping ;) + Eval p = (Eval) stack.pop(); + ops[j] = p; + } + Eval opresult = operation.evaluate(ops); + stack.push(opresult); + } + else if (ptgs[i] instanceof ReferencePtg) { + ReferencePtg ptg = (ReferencePtg) ptgs[i]; + short colnum = ptg.getColumn(); + short rownum = ptg.getRow(); + HSSFRow row = sheet.getRow(rownum); + HSSFCell cell = (row!=null) ? row.getCell(colnum) : null; + pushRef2DEval(ptg, stack, cell, sheet, workbook); + } + else if (ptgs[i] instanceof Ref3DPtg) { + Ref3DPtg ptg = (Ref3DPtg) ptgs[i]; + short colnum = ptg.getColumn(); + short rownum = ptg.getRow(); + HSSFSheet xsheet = workbook.getSheetAt(ptg.getExternSheetIndex()); + HSSFRow row = sheet.getRow(rownum); + HSSFCell cell = (row!=null) ? row.getCell(colnum) : null; + pushRef3DEval(ptg, stack, cell, sheet, workbook); + } + else if (ptgs[i] instanceof AreaPtg) { + AreaPtg ap = (AreaPtg) ptgs[i]; + short row0 = ap.getFirstRow(); + short col0 = ap.getFirstColumn(); + short row1 = ap.getLastRow(); + short col1 = ap.getLastColumn(); + ValueEval[] values = new ValueEval[(row1-row0+1)*(col1-col0+1)]; + for (short x=row0; sheet!=null && x + * special Note: OperationPtg subtypes cannot be passed here! + * @param ptg + * @return + */ + protected static Eval getEvalForPtg(Ptg ptg) { + Eval retval = null; + + Class clazz = (Class) VALUE_EVALS_MAP.get(ptg.getClass()); + try { + if (ptg instanceof Area3DPtg) { + Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY); + retval = (OperationEval) constructor.newInstance(new Ptg[]{ptg}); + } + else if (ptg instanceof AreaPtg) { + Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY); + retval = (OperationEval) constructor.newInstance(new Ptg[]{ptg}); + } + else if (ptg instanceof ReferencePtg) { + Constructor constructor = clazz.getConstructor(REFERENCE_CONSTRUCTOR_CLASS_ARRAY); + retval = (OperationEval) constructor.newInstance(new Ptg[]{ptg}); + } + else if (ptg instanceof Ref3DPtg) { + Constructor constructor = clazz.getConstructor(REF3D_CONSTRUCTOR_CLASS_ARRAY); + retval = (OperationEval) constructor.newInstance(new Ptg[]{ptg}); + } + else { + if (ptg instanceof IntPtg + || ptg instanceof NumberPtg + || ptg instanceof StringPtg + || ptg instanceof BoolPtg + ) { + Constructor constructor = clazz.getConstructor(VALUE_CONTRUCTOR_CLASS_ARRAY); + retval = (ValueEval) constructor.newInstance(new Ptg[]{ptg}); + } + } + } catch (Exception e) { + throw new RuntimeException("Fatal Error: ", e); + } + return retval; + + } + + /** + * Given a cell, find its type and from that create an appropriate ValueEval impl instance + * and return that. Since the cell could be an external reference, we need the sheet that + * this belongs to. + * @param cell + * @param sheet + * @param workbook + * @return + */ + protected static ValueEval getEvalForCell(HSSFCell cell, HSSFSheet sheet, HSSFWorkbook workbook) { + ValueEval retval = null; + if (cell != null) { + switch (cell.getCellType()) { + case HSSFCell.CELL_TYPE_NUMERIC: + retval = new NumberEval(cell.getNumericCellValue()); + break; + case HSSFCell.CELL_TYPE_STRING: + retval = new StringEval(cell.getStringCellValue()); + break; + case HSSFCell.CELL_TYPE_FORMULA: + retval = (ValueEval) evaluate(cell.getCellFormula(), sheet, workbook); + break; + case HSSFCell.CELL_TYPE_BOOLEAN: + retval = new BoolEval(cell.getBooleanCellValue()); + break; + case HSSFCell.CELL_TYPE_BLANK: + retval = new StringEval(""); + break; + case HSSFCell.CELL_TYPE_ERROR: + retval = ErrorEval.ERROR_UNKNOWN; // TODO: think about this... + break; + } + } + return retval; + } + + /** + * create a Ref2DEval for ReferencePtg and push it on the stack. + * @param ptg + * @param stack + * @param cell + * @param sheet + * @param workbook + */ + protected static void pushRef2DEval(ReferencePtg ptg, Stack stack, HSSFCell cell, HSSFSheet sheet, HSSFWorkbook workbook) { + if (cell!=null) + switch (cell.getCellType()) { + case HSSFCell.CELL_TYPE_NUMERIC: + stack.push(new Ref2DEval(ptg, new NumberEval(cell.getNumericCellValue()))); + break; + case HSSFCell.CELL_TYPE_STRING: + stack.push(new Ref2DEval(ptg, new StringEval(cell.getStringCellValue()))); + break; + case HSSFCell.CELL_TYPE_FORMULA: + stack.push(evaluate(cell.getCellFormula(), sheet, workbook)); + break; + case HSSFCell.CELL_TYPE_BOOLEAN: + stack.push(new Ref2DEval(ptg, new BoolEval(cell.getBooleanCellValue()))); + break; + case HSSFCell.CELL_TYPE_BLANK: + stack.push(new Ref2DEval(ptg, new StringEval(""))); + break; + case HSSFCell.CELL_TYPE_ERROR: + stack.push(new Ref2DEval(ptg, ErrorEval.ERROR_UNKNOWN)); // TODO: think about this... + break; + } + else { + stack.push(new Ref2DEval(ptg, new StringEval(""))); + } + } + + /** + * create a Ref3DEval for Ref3DPtg and push it on the stack. + * @param ptg + * @param stack + * @param cell + * @param sheet + * @param workbook + */ + protected static void pushRef3DEval(Ref3DPtg ptg, Stack stack, HSSFCell cell, HSSFSheet sheet, HSSFWorkbook workbook) { + if (cell!=null) + switch (cell.getCellType()) { + case HSSFCell.CELL_TYPE_NUMERIC: + stack.push(new Ref3DEval(ptg, new NumberEval(cell.getNumericCellValue()))); + break; + case HSSFCell.CELL_TYPE_STRING: + stack.push(new Ref3DEval(ptg, new StringEval(cell.getStringCellValue()))); + break; + case HSSFCell.CELL_TYPE_FORMULA: + stack.push(evaluate(cell.getCellFormula(), sheet, workbook)); + break; + case HSSFCell.CELL_TYPE_BOOLEAN: + stack.push(new Ref3DEval(ptg, new BoolEval(cell.getBooleanCellValue()))); + break; + case HSSFCell.CELL_TYPE_BLANK: + stack.push(new Ref3DEval(ptg, new StringEval(""))); + break; + case HSSFCell.CELL_TYPE_ERROR: + stack.push(new Ref3DEval(ptg, ErrorEval.ERROR_UNKNOWN)); // TODO: think about this... + break; + } + else { + stack.push(new Ref3DEval(ptg, new StringEval(""))); + } + } + + + + /** + * Manual testing... needs a c:/temp/test1.xls file to be present. + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String FILE_NAME = "c:/temp/test1.xls"; + + FileInputStream fis = new FileInputStream(FILE_NAME); + HSSFWorkbook wb = new HSSFWorkbook(fis); + fis.close(); + HSSFSheet sheet = wb.getSheetAt(0); + + for (int rn=1, rnSize=4; rn<=rnSize; rn++) { + HSSFRow row = sheet.getRow(rn); + for (int cn=5, cnSize=7; cn<=cnSize; cn++) { + HSSFCell cell = row.getCell((short) cn); + String formula = cell.getCellFormula(); + System.out.println("-----------------------------------------------------"); + //inspectPtgs(formula, sheet, wb); + System.out.println("["+rn+","+cn+"]: "+evaluateToString(formula, sheet, wb)); + System.out.println("-----------------------------------------------------"); + } + } + } + +}