]> source.dussan.org Git - poi.git/commitdiff
Merged revisions 707953,708242,708252,708260,708262,708286 via svnmerge from
authorJosh Micich <josh@apache.org>
Mon, 27 Oct 2008 21:30:02 +0000 (21:30 +0000)
committerJosh Micich <josh@apache.org>
Mon, 27 Oct 2008 21:30:02 +0000 (21:30 +0000)
https://svn.apache.org/repos/asf/poi/trunk

........
  r707953 | josh | 2008-10-26 01:17:06 -0700 (Sun, 26 Oct 2008) | 1 line

  Bugzilla 45966 - added implementation for FIND function (patch from Torstein Tauno Svendsen).
........
  r708242 | nick | 2008-10-27 10:26:52 -0700 (Mon, 27 Oct 2008) | 1 line

  Link typo fix
........
  r708252 | nick | 2008-10-27 10:59:39 -0700 (Mon, 27 Oct 2008) | 1 line

  Patch from bug #46092 - fix hssf dev utility
........
  r708260 | josh | 2008-10-27 11:12:09 -0700 (Mon, 27 Oct 2008) | 1 line

  Removed obsolete class
........
  r708262 | josh | 2008-10-27 11:16:44 -0700 (Mon, 27 Oct 2008) | 1 line

  Bugzilla 46065 - added implementation for VALUE function
........
  r708286 | josh | 2008-10-27 12:24:42 -0700 (Mon, 27 Oct 2008) | 1 line

  Preparation for fix for bug 46009.  (Bug visible on ooxml branch, but this change will expose the problem)
........

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@708325 13f79535-47bb-0310-9956-ffa450edef68

20 files changed:
src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/spreadsheet/formula.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/dev/HSSF.java
src/java/org/apache/poi/hssf/model/Sheet.java
src/java/org/apache/poi/hssf/record/CFHeaderRecord.java
src/java/org/apache/poi/hssf/record/MergeCellsRecord.java
src/java/org/apache/poi/hssf/record/aggregates/MergedCellsTable.java
src/java/org/apache/poi/hssf/record/formula/eval/StringOperationEval.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Find.java
src/java/org/apache/poi/hssf/record/formula/functions/Value.java
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/java/org/apache/poi/hssf/util/CellRangeAddress.java
src/java/org/apache/poi/hssf/util/CellRangeAddressList.java
src/java/org/apache/poi/ss/util/CellRangeAddress.java
src/java/org/apache/poi/ss/util/CellRangeAddressList.java
src/testcases/org/apache/poi/hssf/record/TestMergeCellsRecord.java
src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestFind.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java [new file with mode: 0644]

index 1c6b2854ada22b06673c7c6ed4d935d62d2b6046..183475c20e1b2b558d0aa028e5002d228ee5b7d7 100644 (file)
@@ -37,6 +37,8 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.5-beta4" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">46065 - added implementation for VALUE function</action>
+           <action dev="POI-DEVELOPERS" type="add">45966 - added implementation for FIND function</action>
            <action dev="POI-DEVELOPERS" type="fix">45778 - fixed ObjRecord to read ftLbsData properly</action>
            <action dev="POI-DEVELOPERS" type="fix">46053 - fixed evaluation cache dependency analysis when changing blank cells</action>
         </release>
index d8ced8fb202c03c298e3683b4c4c6e88994a1a9b..3dda9f1819048780185da8fcabc33b85847e70a0 100644 (file)
@@ -99,7 +99,7 @@
                 org.apache.poi.hssf.record.formula.FormulaParser</strong> class. This class implements a hand 
                 written recursive descent parser. 
             </p>
-            <p>Check out the <link href="http://poi.apache.org/javadocs/">javadocs </link> for details. 
+            <p>Check out the <link href="http://poi.apache.org/apidocs/">javadocs </link> for details. 
             </p>
         </section>
        
index bfd9364ce7c975b6a3a600a080253a6df0e348ea..9088ef28bbdaea02fa7bfa62ec6149967f66c35e 100644 (file)
@@ -34,6 +34,8 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.5-beta4" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">46065 - added implementation for VALUE function</action>
+           <action dev="POI-DEVELOPERS" type="add">45966 - added implementation for FIND function</action>
            <action dev="POI-DEVELOPERS" type="fix">45778 - fixed ObjRecord to read ftLbsData properly</action>
            <action dev="POI-DEVELOPERS" type="fix">46053 - fixed evaluation cache dependency analysis when changing blank cells</action>
         </release>
index 07baa3a2ba83dae9f1166ba41d0606fcf7e95557..c1af8a11e47eb2a878ee349e38c80853becff23d 100644 (file)
@@ -15,7 +15,6 @@
    limitations under the License.
 ==================================================================== */
 
-
 package org.apache.poi.hssf.dev;
 
 import java.io.FileInputStream;
@@ -30,7 +29,7 @@ import org.apache.poi.hssf.usermodel.HSSFRichTextString;
 import org.apache.poi.hssf.usermodel.HSSFRow;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.ss.util.Region;
 
@@ -222,7 +221,7 @@ public class HSSF
         if (args.length < 2)
         {
 
-/*            try
+            try
             {
                 HSSF hssf = new HSSF(args[ 0 ]);
 
@@ -231,26 +230,30 @@ public class HSSF
 
                 for (int k = 0; k < wb.getNumberOfSheets(); k++)
                 {
-                    System.out.println("Sheet " + k);
                     HSSFSheet sheet = wb.getSheetAt(k);
                     int       rows  = sheet.getPhysicalNumberOfRows();
-
+                    System.out.println("Sheet " + k + " \""
+                                       + wb.getSheetName(k) + "\" has "
+                                       + rows + " row(s).");
                     for (int r = 0; r < rows; r++)
                     {
-                        HSSFRow row   = sheet.getPhysicalRowAt(r);
-                        int     cells = row.getPhysicalNumberOfCells();
-
-                        System.out.println("ROW " + row.getRowNum());
+                        HSSFRow row   = sheet.getRow(r);
+                        int     cells = (row != null) ? row.getPhysicalNumberOfCells() : 0;
+                        if (row != null) {
+                          System.out.println("\nROW " + row.getRowNum()
+                                             + " has " + cells + " cell(s).");
+                        }
                         for (int c = 0; c < cells; c++)
                         {
-                            HSSFCell cell  = row.getPhysicalCellAt(c);
+                            HSSFCell cell  = row.getCell(c);
                             String   value = null;
 
                             switch (cell.getCellType())
                             {
 
                                 case HSSFCell.CELL_TYPE_FORMULA :
-                                    value = "FORMULA ";
+                                    value = "FORMULA value="
+                                    + cell.getCellFormula();
                                     break;
 
                                 case HSSFCell.CELL_TYPE_NUMERIC :
@@ -275,7 +278,7 @@ public class HSSF
             catch (Exception e)
             {
                 e.printStackTrace();
-            }*/
+            }
         }
         else if (args.length == 2)
         {
index c5e78af44d424775206b78f2e002d7d4ad4eec16..901402eff0e349d514ae19aedaf80e7dbeba20e0 100644 (file)
@@ -68,7 +68,7 @@ import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
 import org.apache.poi.hssf.record.aggregates.RecordAggregate.PositionTrackingVisitor;
 import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
 import org.apache.poi.hssf.record.formula.FormulaShifter;
-import org.apache.poi.hssf.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.hssf.util.PaneInformation;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
index 708b20d857967cd299eecba8ef0f47d72f658f72..762af3be7977f4d36135f9308a9ff329555bba16 100644 (file)
@@ -51,8 +51,8 @@ public final class CFHeaderRecord extends Record {
        {
                field_1_numcf = in.readShort();
                field_2_need_recalculation = in.readShort();
-               field_3_enclosing_cell_range = new org.apache.poi.hssf.util.CellRangeAddress(in);
-               field_4_cell_ranges = new org.apache.poi.hssf.util.CellRangeAddressList(in);
+               field_3_enclosing_cell_range = new CellRangeAddress(in);
+               field_4_cell_ranges = new CellRangeAddressList(in);
        }
        
        public int getNumberOfConditionalFormats()
index 7683c6b863dde0eac2472fd862c3087f63badd37..1b917a7fce77b16641524d1b393d7998de290a4e 100644 (file)
@@ -50,7 +50,7 @@ public final class MergeCellsRecord extends Record {
        int nRegions = in.readUShort();
        CellRangeAddress[] cras = new CellRangeAddress[nRegions];
        for (int i = 0; i < nRegions; i++) {
-                       cras[i] = new org.apache.poi.hssf.util.CellRangeAddress(in);
+                       cras[i] = new CellRangeAddress(in);
                }
        _numberOfRegions = nRegions;
        _startIndex = 0;
index bbf5c4d0a04b39e06ddcf5bb93ebb38ac6a1ebc2..588276274fd3a598c0c196672c14190d44ef5500 100644 (file)
@@ -22,8 +22,8 @@ import java.util.List;
 
 import org.apache.poi.hssf.model.RecordStream;
 import org.apache.poi.hssf.record.MergeCellsRecord;
-import org.apache.poi.hssf.util.CellRangeAddress;
-import org.apache.poi.hssf.util.CellRangeAddressList;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddressList;
 
 /**
  * 
@@ -51,7 +51,8 @@ public final class MergedCellsTable extends RecordAggregate {
                        MergeCellsRecord mcr = (MergeCellsRecord) rs.getNext();
                        int nRegions = mcr.getNumAreas();
                        for (int i = 0; i < nRegions; i++) {
-                               temp.add(mcr.getAreaAt(i));
+                               CellRangeAddress cra = mcr.getAreaAt(i);
+                               temp.add(cra);
                        }
                }
        }
@@ -102,7 +103,8 @@ public final class MergedCellsTable extends RecordAggregate {
        private void addMergeCellsRecord(MergeCellsRecord mcr) {
                int nRegions = mcr.getNumAreas();
                for (int i = 0; i < nRegions; i++) {
-                       _mergedRegions.add(mcr.getAreaAt(i));
+                       CellRangeAddress cra = mcr.getAreaAt(i);
+                       _mergedRegions.add(cra);
                }
        }
 
@@ -130,5 +132,4 @@ public final class MergedCellsTable extends RecordAggregate {
        public int getNumberOfMergedRegions() {
                return _mergedRegions.size();
        }
-
 }
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/StringOperationEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/StringOperationEval.java
deleted file mode 100644 (file)
index e2a3c72..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 14, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.eval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public abstract class StringOperationEval implements OperationEval {
-
-
-
-    /**
-     * Returns an instanceof StringValueEval or ErrorEval or BlankEval
-     * 
-     * @param eval
-     * @param srcRow
-     * @param srcCol
-     */
-    protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) {
-        ValueEval retval;
-        if (eval instanceof AreaEval) {
-            AreaEval ae = (AreaEval) eval;
-            if (ae.contains(srcRow, srcCol)) { // circular ref!
-                retval = ErrorEval.CIRCULAR_REF_ERROR;
-            }
-            else if (ae.isRow()) {
-                if (ae.containsColumn(srcCol)) {
-                    ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
-                    retval = internalResolveEval(eval);
-                }
-                else {
-                    retval = ErrorEval.NAME_INVALID;
-                }
-            }
-            else if (ae.isColumn()) {
-                if (ae.containsRow(srcRow)) {
-                    ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
-                    retval = internalResolveEval(eval);
-                }
-                else {
-                    retval = ErrorEval.NAME_INVALID;
-                }
-            }
-            else {
-                retval = ErrorEval.NAME_INVALID;
-            }
-        }
-        else {
-            retval = internalResolveEval(eval);
-        }
-        return retval;
-    }
-
-    private ValueEval internalResolveEval(Eval eval) {
-        ValueEval retval;
-        if (eval instanceof StringValueEval) {
-            retval = (StringValueEval) eval;
-        }
-        else if (eval instanceof RefEval) {
-            RefEval re = (RefEval) eval;
-            ValueEval tve = re.getInnerValueEval();
-            if (tve instanceof StringValueEval || tve instanceof BlankEval) {
-                retval = tve;
-            }
-            else {
-                retval = ErrorEval.NAME_INVALID;
-            }
-        }
-        else if (eval instanceof BlankEval) {
-            retval = (BlankEval) eval;
-        }
-        else {
-            retval = ErrorEval.NAME_INVALID;
-        }
-        return retval;
-    }
-}
index 7bd11ecf3402d5dd6c644fce831dab33632e1d82..5621eb5cea37ed3316047ec238ea16c44768ffb3 100644 (file)
@@ -1,25 +1,65 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+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.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+
+/**
+ * Implementation of the FIND() function.<p/>
+ *
+ * <b>Syntax</b>:<br/>
+ * <b>FIND</b>(<b>find_text</b>, <b>within_text</b>, start_num)<p/>
  *
+ * FIND returns the character position of the first occurrence of <tt>find_text</tt> inside 
+ * <tt>within_text</tt>.  The third parameter, <tt>start_num</tt>, is optional (default=1)
+ * and specifies where to start searching from.  Character positions are 1-based.<p/>
+ *
+ * @author Torstein Tauno Svendsen (torstei@officenet.no)
  */
-package org.apache.poi.hssf.record.formula.functions;
+public class Find extends TextFunction {
 
-public class Find extends NotImplementedFunction {
+       protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+                       throws EvaluationException {
 
+               int nArgs = args.length;
+               if (nArgs < 2 || nArgs > 3) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+               String needle = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+               String haystack = evaluateStringArg(args[1], srcCellRow, srcCellCol);
+               int startpos;
+               if (nArgs == 3) {
+                       startpos = evaluateIntArg(args[2], srcCellRow, srcCellCol);
+                       if (startpos <= 0) {
+                               return ErrorEval.VALUE_INVALID;
+                       }
+                       startpos--; // convert 1-based to zero based
+               } else {
+                       startpos = 0;
+               }
+               int result = haystack.indexOf(needle, startpos);
+               if (result == -1) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+               return new NumberEval(result + 1);
+       }
 }
index 6772dcf2836e2e4af5ae38829b1388689914a64b..84f61db98e7b79539015fc52a15acefda7739a10 100644 (file)
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
- *
- */
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Value extends NotImplementedFunction {
+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.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Implementation for Excel VALUE() function.<p/>
+ * 
+ * <b>Syntax</b>:<br/> <b>VALUE</b>(<b>text</b>)<br/>
+ * 
+ * Converts the text argument to a number. Leading and/or trailing whitespace is
+ * ignored. Currency symbols and thousands separators are stripped out.
+ * Scientific notation is also supported. If the supplied text does not convert
+ * properly the result is <b>#VALUE!</b> error. Blank string converts to zero.
+ * 
+ * @author Josh Micich
+ */
+public final class Value implements Function {
+
+       /** "1,0000" is valid, "1,00" is not */
+       private static final int MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR = 4;
+       private static final Double ZERO = new Double(0.0);
+
+       public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+               if (args.length != 1) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+               ValueEval veText;
+               try {
+                       veText = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+               String strText = OperandResolver.coerceValueToString(veText);
+               Double result = convertTextToNumber(strText);
+               if (result == null) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+               return new NumberEval(result.doubleValue());
+       }
+
+       /**
+        * TODO see if the same functionality is needed in {@link OperandResolver#parseDouble(String)} 
+        * 
+        * @return <code>null</code> if there is any problem converting the text
+        */
+       private static Double convertTextToNumber(String strText) {
+               boolean foundCurrency = false;
+               boolean foundUnaryPlus = false;
+               boolean foundUnaryMinus = false;
+
+               int len = strText.length();
+               int i;
+               for (i = 0; i < len; i++) {
+                       char ch = strText.charAt(i);
+                       if (Character.isDigit(ch) || ch == '.') {
+                               break;
+                       }
+                       switch (ch) {
+                               case ' ':
+                                       // intervening spaces between '$', '-', '+' are OK
+                                       continue;
+                               case '$':
+                                       if (foundCurrency) {
+                                               // only one currency symbols is allowed
+                                               return null;
+                                       }
+                                       foundCurrency = true;
+                                       continue;
+                               case '+':
+                                       if (foundUnaryMinus || foundUnaryPlus) {
+                                               return null;
+                                       }
+                                       foundUnaryPlus = true;
+                                       continue;
+                               case '-':
+                                       if (foundUnaryMinus || foundUnaryPlus) {
+                                               return null;
+                                       }
+                                       foundUnaryMinus = true;
+                                       continue;
+                               default:
+                                       // all other characters are illegal
+                                       return null;
+                       }
+               }
+               if (i >= len) {
+                       // didn't find digits or '.'
+                       if (foundCurrency || foundUnaryMinus || foundUnaryPlus) {
+                               return null;
+                       }
+                       return ZERO;
+               }
+
+               // remove thousands separators
+
+               boolean foundDecimalPoint = false;
+               int lastThousandsSeparatorIndex = Short.MIN_VALUE;
 
+               StringBuffer sb = new StringBuffer(len);
+               for (; i < len; i++) {
+                       char ch = strText.charAt(i);
+                       if (Character.isDigit(ch)) {
+                               sb.append(ch);
+                               continue;
+                       }
+                       switch (ch) {
+                               case ' ':
+                                       String remainingText = strText.substring(i);
+                                       if (remainingText.trim().length() > 0) {
+                                               // intervening spaces not allowed once the digits start
+                                               return null;
+                                       }
+                                       break;
+                               case '.':
+                                       if (foundDecimalPoint) {
+                                               return null;
+                                       }
+                                       if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+                                               return null;
+                                       }
+                                       foundDecimalPoint = true;
+                                       sb.append('.');
+                                       continue;
+                               case ',':
+                                       if (foundDecimalPoint) {
+                                               // thousands separators not allowed after '.' or 'E'
+                                               return null;
+                                       }
+                                       int distanceBetweenThousandsSeparators = i - lastThousandsSeparatorIndex;
+                                       // as long as there are 3 or more digits between
+                                       if (distanceBetweenThousandsSeparators < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+                                               return null;
+                                       }
+                                       lastThousandsSeparatorIndex = i;
+                                       // don't append ','
+                                       continue;
+       
+                               case 'E':
+                               case 'e':
+                                       if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+                                               return null;
+                                       }
+                                       // append rest of strText and skip to end of loop
+                                       sb.append(strText.substring(i));
+                                       i = len;
+                                       break;
+                               default:
+                                       // all other characters are illegal
+                                       return null;
+                       }
+               }
+               if (!foundDecimalPoint) {
+                       if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+                               return null;
+                       }
+               }
+               double d;
+               try {
+                       d = Double.parseDouble(sb.toString());
+               } catch (NumberFormatException e) {
+                       // still a problem parsing the number - probably out of range
+                       return null;
+               }
+               return new Double(foundUnaryMinus ? -d : d);
+       }
 }
index 75568f4dad5147b71fd8faa31da5fdc58e039048..fd0e0a53591648f39520a5b08cd0719a0fb437ed 100644 (file)
@@ -670,7 +670,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
     /**
      * @return the merged region at the specified index
      */
-    public org.apache.poi.hssf.util.CellRangeAddress getMergedRegion(int index) {
+    public CellRangeAddress getMergedRegion(int index) {
         return sheet.getMergedRegionAt(index);
     }
 
index cc67b8eb05619af0528acce23008320dea358c67..439db43dbe7c5e459a764b2bfad94dd83f511fe6 100644 (file)
@@ -18,12 +18,12 @@ package org.apache.poi.hssf.util;
 \r
 import org.apache.poi.hssf.record.RecordInputStream;\r
 import org.apache.poi.hssf.record.SelectionRecord;\r
-import org.apache.poi.util.LittleEndian;\r
 \r
 /**\r
  * See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>\r
  * \r
  * Note - {@link SelectionRecord} uses the BIFF5 version of this structure\r
+ * @deprecated use {@link org.apache.poi.ss.util.CellRangeAddress}\r
  * @author Dragos Buleandra (dragos.buleandra@trade2b.ro)\r
  */\r
 public class CellRangeAddress extends org.apache.poi.ss.util.CellRangeAddress {\r
index 79ea50abb446fc80a73e2717de634fa94d03e418..5f22fb733636c3b2c50dc0eb62496d8e89872bd0 100644 (file)
@@ -33,6 +33,8 @@ import org.apache.poi.util.LittleEndian;
  * range address (called an ADDR structure) contains 4 16-bit-values.
  * </p>
  * 
+ * @deprecated use {@link org.apache.poi.ss.util.CellRangeAddressList}
+ * 
  * @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
  */
 public class CellRangeAddressList extends org.apache.poi.ss.util.CellRangeAddressList {
index 0d910c68246632d1ee3ba1fced2fe2633462c05e..3cc70cf48320b0b00b1ad38e31bc24db3ed44fa8 100644 (file)
@@ -16,6 +16,7 @@
 
 package org.apache.poi.ss.util;
 
+import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.record.SelectionRecord;
 import org.apache.poi.util.LittleEndian;
 
@@ -42,6 +43,17 @@ public class CellRangeAddress extends CellRangeAddressBase {
                LittleEndian.putUShort(data, offset + 6, getLastColumn());
                return ENCODED_SIZE;
        }
+       public CellRangeAddress(RecordInputStream in) {
+               super(readUShortAndCheck(in), in.readUShort(), in.readUShort(), in.readUShort());
+       }
+
+       private static int readUShortAndCheck(RecordInputStream in) {
+               if (in.remaining() < ENCODED_SIZE) {
+                       // Ran out of data
+                       throw new RuntimeException("Ran out of data reading CellRangeAddress");
+               }
+               return in.readUShort();
+       }
 
        public CellRangeAddress copy() {
                return new CellRangeAddress(getFirstRow(), getLastRow(), getFirstColumn(), getLastColumn());
index 72b5882488ed155cc9c3880656a8cfcbade46120..65474ef980a4727e24a16c361edd6ebd5dd67d86 100644 (file)
@@ -18,6 +18,8 @@ package org.apache.poi.ss.util;
 
 import java.util.ArrayList;
 import java.util.List;
+
+import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.util.LittleEndian;
 
 /**
@@ -51,7 +53,17 @@ public class CellRangeAddressList {
                this();
                addCellRangeAddress(firstRow, firstCol, lastRow, lastCol);
        }
+       /**
+        * @param in the RecordInputstream to read the record from
+        */
+       public CellRangeAddressList(RecordInputStream in) {
+               this();
+               int nItems = in.readUShort();
 
+               for (int k = 0; k < nItems; k++) {
+                       _list.add(new CellRangeAddress(in));
+               }
+       }
        /**
         * Get the number of following ADDR structures. The number of this
         * structures is automatically set when reading an Excel file and/or
index c0a8f9fe74b9ff2614f797a994d30072f63d143f..b36da1aadfec04a439d45fce389b0a318fd3cf86 100644 (file)
 
 package org.apache.poi.hssf.record;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
+import org.apache.poi.hssf.model.RecordStream;
+import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
+import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
 import org.apache.poi.ss.util.CellRangeAddress;
 
+
 /**
  * Make sure the merge cells record behaves
  * @author Danny Mui (dmui at apache dot org)
@@ -28,25 +36,45 @@ import org.apache.poi.ss.util.CellRangeAddress;
  */
 public final class TestMergeCellsRecord extends TestCase {
    
-   /**
-    * Make sure when a clone is called, we actually clone it.
-    * @throws Exception
-    */
-   public void testCloneReferences() throws Exception {
-      CellRangeAddress[] cras = { new CellRangeAddress(0, 1, 0, 2), };
-      MergeCellsRecord merge = new MergeCellsRecord(cras, 0, cras.length);
-      MergeCellsRecord clone = (MergeCellsRecord)merge.clone();
-      
-      assertNotSame("Merged and cloned objects are the same", merge, clone);
-      
-      CellRangeAddress mergeRegion = merge.getAreaAt(0);
-      CellRangeAddress cloneRegion = clone.getAreaAt(0);
-      assertNotSame("Should not point to same objects when cloning", mergeRegion, cloneRegion);
-      assertEquals("New Clone Row From doesnt match", mergeRegion.getFirstRow(), cloneRegion.getFirstRow());
-      assertEquals("New Clone Row To doesnt match", mergeRegion.getLastRow(), cloneRegion.getLastRow());
-      assertEquals("New Clone Col From doesnt match", mergeRegion.getFirstColumn(), cloneRegion.getFirstColumn());
-      assertEquals("New Clone Col To doesnt match", mergeRegion.getLastColumn(), cloneRegion.getLastColumn());      
+       /**
+        * Make sure when a clone is called, we actually clone it.
+        */
+       public void testCloneReferences() {
+               CellRangeAddress[] cras = { new CellRangeAddress(0, 1, 0, 2), };
+               MergeCellsRecord merge = new MergeCellsRecord(cras, 0, cras.length);
+               MergeCellsRecord clone = (MergeCellsRecord)merge.clone();
+
+               assertNotSame("Merged and cloned objects are the same", merge, clone);
+
+               CellRangeAddress mergeRegion = merge.getAreaAt(0);
+               CellRangeAddress cloneRegion = clone.getAreaAt(0);
+               assertNotSame("Should not point to same objects when cloning", mergeRegion, cloneRegion);
+               assertEquals("New Clone Row From doesnt match", mergeRegion.getFirstRow(), cloneRegion.getFirstRow());
+               assertEquals("New Clone Row To doesnt match", mergeRegion.getLastRow(), cloneRegion.getLastRow());
+               assertEquals("New Clone Col From doesnt match", mergeRegion.getFirstColumn(), cloneRegion.getFirstColumn());
+               assertEquals("New Clone Col To doesnt match", mergeRegion.getLastColumn(), cloneRegion.getLastColumn());      
       
-      assertFalse(merge.getAreaAt(0) == clone.getAreaAt(0));
-   }
+               assertFalse(merge.getAreaAt(0) == clone.getAreaAt(0));
+       }
+   
+       private static final RecordVisitor dummyRecordVisitor = new RecordVisitor() {
+               public void visitRecord(Record r) {
+                       // do nothing
+               }
+       };
+       public void testMCTable_bug46009() {
+               MergedCellsTable mct = new MergedCellsTable();
+               List recList = new ArrayList();
+               CellRangeAddress[] cras = new CellRangeAddress[] {
+                               new CellRangeAddress(0, 0, 0, 3), 
+               };
+               recList.add(new MergeCellsRecord(cras, 0, 1));
+               RecordStream rs = new RecordStream(recList, 0);
+               mct.read(rs);
+               try {
+                       mct.visitContainedRecords(dummyRecordVisitor);
+               } catch (ArrayStoreException e) {
+                       throw new AssertionFailedError("Identified bug 46009");
+               }
+       }
 }
index c57c40b62add6b39859c186423af71f2f0365c2b..834b5281d893dc38b2d92dcc8dfccae6fa3b4cc1 100755 (executable)
@@ -32,6 +32,7 @@ public final class AllIndividualFunctionEvaluationTests {
                result.addTestSuite(TestAverage.class);
                result.addTestSuite(TestCountFuncs.class);
                result.addTestSuite(TestDate.class);
+               result.addTestSuite(TestFind.class);
                result.addTestSuite(TestFinanceLib.class);
                result.addTestSuite(TestIndex.class);
                result.addTestSuite(TestIndexFunctionFromSpreadsheet.class);
@@ -49,6 +50,7 @@ public final class AllIndividualFunctionEvaluationTests {
                result.addTestSuite(TestStatsLib.class);
                result.addTestSuite(TestTFunc.class);
                result.addTestSuite(TestTrim.class);
+               result.addTestSuite(TestValue.class);
                result.addTestSuite(TestXYNumericFunction.class);
                return result;
        }
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFind.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFind.java
new file mode 100644 (file)
index 0000000..3a6df73
--- /dev/null
@@ -0,0 +1,76 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.CellValue;
+
+/**
+ * Tests for {@link Find}
+ * 
+ * @author Torstein Svendsen (torstei@officenet.no)
+ */
+public final class TestFind extends TestCase {
+
+       public void testFind() {
+               HSSFWorkbook wb = new HSSFWorkbook();
+               HSSFCell cell = wb.createSheet().createRow(0).createCell(0);
+
+               HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+
+               confirmResult(fe, cell, "find(\"h\", \"haystack\")", 1);
+               confirmResult(fe, cell, "find(\"a\", \"haystack\",2)", 2);
+               confirmResult(fe, cell, "find(\"a\", \"haystack\",3)", 6);
+
+               // number args converted to text
+               confirmResult(fe, cell, "find(7, 32768)", 3);
+               confirmResult(fe, cell, "find(\"34\", 1341235233412, 3)", 10);
+               confirmResult(fe, cell, "find(5, 87654)", 4);
+
+               // Errors
+               confirmError(fe, cell, "find(\"n\", \"haystack\")", HSSFErrorConstants.ERROR_VALUE);
+               confirmError(fe, cell, "find(\"k\", \"haystack\",9)", HSSFErrorConstants.ERROR_VALUE);
+               confirmError(fe, cell, "find(\"k\", \"haystack\",#REF!)", HSSFErrorConstants.ERROR_REF);
+               confirmError(fe, cell, "find(\"k\", \"haystack\",0)", HSSFErrorConstants.ERROR_VALUE);
+               confirmError(fe, cell, "find(#DIV/0!, #N/A, #REF!)", HSSFErrorConstants.ERROR_DIV_0);
+               confirmError(fe, cell, "find(2, #N/A, #REF!)", HSSFErrorConstants.ERROR_NA);
+       }
+
+       private static void confirmResult(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,
+                       int expectedResult) {
+               cell.setCellFormula(formulaText);
+               fe.notifyUpdateCell(cell);
+               CellValue result = fe.evaluate(cell);
+               assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_NUMERIC);
+               assertEquals(expectedResult, result.getNumberValue(), 0.0);
+       }
+
+       private static void confirmError(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,
+                       int expectedErrorCode) {
+               cell.setCellFormula(formulaText);
+               fe.notifyUpdateCell(cell);
+               CellValue result = fe.evaluate(cell);
+               assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_ERROR);
+               assertEquals(expectedErrorCode, result.getErrorValue());
+       }
+}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java
new file mode 100644 (file)
index 0000000..5f74fbf
--- /dev/null
@@ -0,0 +1,94 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.TestCase;
+
+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.StringEval;
+
+/**
+ * Tests for {@link Value}
+ * 
+ * @author Josh Micich
+ */
+public final class TestValue extends TestCase {
+
+       private static Eval invokeValue(String strText) {
+               Eval[] args = new Eval[] { new StringEval(strText), };
+               return new Value().evaluate(args, -1, (short) -1);
+       }
+
+       private static void confirmValue(String strText, double expected) {
+               Eval result = invokeValue(strText);
+               assertEquals(NumberEval.class, result.getClass());
+               assertEquals(expected, ((NumberEval) result).getNumberValue(), 0.0);
+       }
+
+       private static void confirmValueError(String strText) {
+               Eval result = invokeValue(strText);
+               assertEquals(ErrorEval.class, result.getClass());
+               assertEquals(ErrorEval.VALUE_INVALID, result);
+       }
+
+       public void testBasic() {
+
+               confirmValue("100", 100);
+               confirmValue("-2.3", -2.3);
+               confirmValue(".5", 0.5);
+               confirmValue(".5e2", 50);
+               confirmValue(".5e-2", 0.005);
+               confirmValue(".5e+2", 50);
+               confirmValue("+5", 5);
+               confirmValue("$1,000", 1000);
+               confirmValue("100.5e1", 1005);
+               confirmValue("1,0000", 10000);
+               confirmValue("1,000,0000", 10000000);
+               confirmValue("1,000,0000,00000", 1000000000000.0);
+               confirmValue(" 100 ", 100);
+               confirmValue(" + 100", 100);
+               confirmValue("10000", 10000);
+               confirmValue("$-5", -5);
+               confirmValue("$.5", 0.5);
+               confirmValue("123e+5", 12300000);
+               confirmValue("1,000e2", 100000);
+               confirmValue("$10e2", 1000);
+               confirmValue("$1,000e2", 100000);
+       }
+
+       public void testErrors() {
+               confirmValueError("1+1");
+               confirmValueError("1 1");
+               confirmValueError("1,00.0");
+               confirmValueError("1,00");
+               confirmValueError("$1,00.5e1");
+               confirmValueError("1,00.5e1");
+               confirmValueError("1,0,000");
+               confirmValueError("1,00,000");
+               confirmValueError("++100");
+               confirmValueError("$$5");
+               confirmValueError("-");
+               confirmValueError("+");
+               confirmValueError("$");
+               confirmValueError(",300");
+               confirmValueError("0.233,4");
+               confirmValueError("1e2.5");
+       }
+}