_chooseFuncOffset = -1;
}
- public AttrPtg(LittleEndianInput in)
- {
+ public AttrPtg(LittleEndianInput in) {
field_1_options = in.readByte();
field_2_data = in.readShort();
if (isOptimizedChoose()) {
return new AttrPtg(space.set(0), data, null, -1);
}
- public void setOptions(byte options)
- {
- field_1_options = options;
+ public static AttrPtg getSumSingle() {
+ return new AttrPtg(sum.set(0), 0, null, -1);
}
- public byte getOptions()
- {
- return field_1_options;
- }
- public boolean isSemiVolatile()
- {
- return semiVolatile.isSet(getOptions());
+ public boolean isSemiVolatile() {
+ return semiVolatile.isSet(field_1_options);
}
- public boolean isOptimizedIf()
- {
- return optiIf.isSet(getOptions());
+ public boolean isOptimizedIf() {
+ return optiIf.isSet(field_1_options);
}
- public boolean isOptimizedChoose()
- {
- return optiChoose.isSet(getOptions());
+ public boolean isOptimizedChoose() {
+ return optiChoose.isSet(field_1_options);
}
// lets hope no one uses this anymore
- public boolean isGoto()
- {
- return optGoto.isSet(getOptions());
- }
-
- public boolean isSum()
- {
- return sum.isSet(getOptions());
+ public boolean isGoto() {
+ return optGoto.isSet(field_1_options);
}
- public void setSum(boolean bsum) {
- field_1_options=sum.setByteBoolean(field_1_options,bsum);
+ public boolean isSum() {
+ return sum.isSet(field_1_options);
}
public void setOptimizedIf(boolean bif) {
}
// lets hope no one uses this anymore
- public boolean isBaxcel()
- {
- return baxcel.isSet(getOptions());
+ private boolean isBaxcel() {
+ return baxcel.isSet(field_1_options);
}
// biff3&4 only shouldn't happen anymore
- public boolean isSpace()
- {
- return space.isSet(getOptions());
+ public boolean isSpace() {
+ return space.isSet(field_1_options);
}
- public void setData(short data)
- {
+ public void setData(short data) {
field_2_data = data;
}
- public short getData()
- {
+ public short getData() {
return field_2_data;
}
}
}
- public int getSize()
- {
+ public int getSize() {
if (_jumpTable != null) {
return SIZE + (_jumpTable.length + 1) * LittleEndian.SHORT_SIZE;
}
if(space.isSet(field_1_options)) {
return operands[ 0 ];
} else if (optiIf.isSet(field_1_options)) {
- return toFormulaString() + "(" + operands[ 0 ] +")";
+ return toFormulaString() + "(" + operands[0] + ")";
} else if (optGoto.isSet(field_1_options)) {
return toFormulaString() + operands[0]; //goto isn't a real formula element should not show up
} else {
- return toFormulaString() + "(" + operands[ 0 ] + ")";
+ return toFormulaString() + "(" + operands[0] + ")";
}
}
- public int getNumberOfOperands()
- {
+ public int getNumberOfOperands() {
return 1;
}
- public int getType()
- {
+ public int getType() {
return -1;
}
if (_jumpTable == null) {
jt = null;
} else {
- jt = (int[]) _jumpTable.clone();
+ jt = _jumpTable.clone();
}
return new AttrPtg(field_1_options, field_2_data, jt, _chooseFuncOffset);
}
import java.util.HashMap;
import java.util.Map;
+import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
import org.apache.poi.hssf.record.formula.functions.*;
/**
* Some function IDs that require special treatment
*/
private static final class FunctionID {
+ /** 4 */
+ public static final int SUM = FunctionMetadataRegistry.FUNCTION_INDEX_SUM;
/** 78 */
public static final int OFFSET = 78;
/** 148 */
public static final int INDIRECT = 148;
/** 255 */
- public static final int EXTERNAL_FUNC = 255;
+ public static final int EXTERNAL_FUNC = FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL;
}
// convenient access to namespace
private static final FunctionID ID = null;
retval[1] = new If(); // IF
retval[2] = new IsNa(); // ISNA
retval[3] = new IsError(); // ISERROR
- retval[4] = AggregateFunction.SUM;
+ retval[ID.SUM] = AggregateFunction.SUM;
retval[5] = AggregateFunction.AVERAGE;
retval[6] = AggregateFunction.MIN;
retval[7] = AggregateFunction.MAX;
*/
public static final String FUNCTION_NAME_IF = "IF";
+ public static final short FUNCTION_INDEX_SUM = 4;
public static final short FUNCTION_INDEX_EXTERNAL = 255;
private static FunctionMetadataRegistry _instance;
private final FunctionMetadata[] _functionDataByIndex;
- private final Map _functionDataByName;
+ private final Map<String, FunctionMetadata> _functionDataByName;
private static FunctionMetadataRegistry getInstance() {
if (_instance == null) {
return _instance;
}
- /* package */ FunctionMetadataRegistry(FunctionMetadata[] functionDataByIndex, Map functionDataByName) {
+ /* package */ FunctionMetadataRegistry(FunctionMetadata[] functionDataByIndex, Map<String, FunctionMetadata> functionDataByName) {
_functionDataByIndex = functionDataByIndex;
_functionDataByName = functionDataByName;
}
- /* package */ Set getAllFunctionNames() {
+ /* package */ Set<String> getAllFunctionNames() {
return _functionDataByName.keySet();
}
}
private FunctionMetadata getFunctionByNameInternal(String name) {
- return (FunctionMetadata) _functionDataByName.get(name);
+ return _functionDataByName.get(name);
}
import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.ArrayPtg;
+import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.BoolPtg;
import org.apache.poi.hssf.record.formula.ConcatPtg;
import org.apache.poi.hssf.record.formula.DividePtg;
}
boolean isVarArgs = !fm.hasFixedArgsLength();
int funcIx = fm.getIndex();
- if (false && funcIx == 4 && args.length == 1) {
- // TODO - make POI behave more like Excel when summing a single argument:
- // return new ParseNode(AttrPtg.getSumSingle(), args);
+ if (funcIx == FunctionMetadataRegistry.FUNCTION_INDEX_SUM && args.length == 1) {
+ // Excel encodes the sum of a single argument as tAttrSum
+ // POI does the same for consistency, but this is not critical
+ return new ParseNode(AttrPtg.getSumSingle(), args);
+ // The code below would encode tFuncVar(SUM) which seems to do no harm
}
validateNumArgs(args.length, fm);
package org.apache.poi.ss.formula;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
+import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.ControlPtg;
+import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.MemFuncPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.RangePtg;
return;
}
+ if (isSingleArgSum(token)) {
+ // Need to process the argument of SUM with transformFunctionNode below
+ // so make a dummy FuncVarPtg for that call.
+ token = new FuncVarPtg("SUM", (byte)1);
+ // Note - the tAttrSum token (node.getToken()) is a base
+ // token so does not need to have its operand class set
+ }
if (token instanceof ValueOperatorPtg || token instanceof ControlPtg
|| token instanceof MemFuncPtg
|| token instanceof UnionPtg) {
token.setClass(transformClass(token.getPtgClass(), desiredOperandClass, callerForceArrayFlag));
}
+ private static boolean isSingleArgSum(Ptg token) {
+ if (token instanceof AttrPtg) {
+ AttrPtg attrPtg = (AttrPtg) token;
+ return attrPtg.isSum();
+ }
+ return false;
+ }
+
private static boolean isSimpleValueFunction(Ptg token) {
if (token instanceof AbstractFunctionPtg) {
AbstractFunctionPtg aptg = (AbstractFunctionPtg) token;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
-import org.apache.poi.hssf.record.formula.FuncVarPtg;
+import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.usermodel.HSSFCell;
confirmParseFormula(workbook);
// And make it non-contiguous
- if (false) { // TODO (Nov 2008) - make the formula parser support area unions
- name.setReference("A1:A2,C3");
- }
+ // using area unions
+ name.setReference("A1:A2,C3");
confirmParseFormula(workbook);
}
Ptg[] ptgs = HSSFFormulaParser.parse("SUM(testName)", workbook);
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
assertEquals(NamePtg.class, ptgs[0].getClass());
- assertEquals(FuncVarPtg.class, ptgs[1].getClass());
+ assertEquals(AttrPtg.class, ptgs[1].getClass());
}
public void testEvaluateFormulaWithRowBeyond32768_Bug44539() {