LCOV - code coverage report
Current view: top level - sc/source/core/tool - compare.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 35 133 26.3 %
Date: 2014-11-03 Functions: 5 9 55.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "compare.hxx"
      21             : 
      22             : #include "document.hxx"
      23             : #include "docoptio.hxx"
      24             : 
      25             : #include <unotools/textsearch.hxx>
      26             : 
      27             : namespace sc {
      28             : 
      29        6168 : Compare::Cell::Cell() :
      30        6168 :     mfValue(0.0), mbValue(false), mbEmpty(false) {}
      31             : 
      32        3084 : Compare::Compare() :
      33        3084 :     meOp(SC_EQUAL), mbIgnoreCase(true) {}
      34             : 
      35           0 : CompareOptions::CompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ) :
      36             :     aQueryEntry(rEntry),
      37             :     bRegEx(bReg),
      38           0 :     bMatchWholeCell(pDoc->GetDocOptions().IsMatchWholeCell())
      39             : {
      40           0 :     bRegEx = (bRegEx && (aQueryEntry.eOp == SC_EQUAL || aQueryEntry.eOp == SC_NOT_EQUAL));
      41             :     // Interpreter functions usually are case insensitive, except the simple
      42             :     // comparison operators, for which these options aren't used. Override in
      43             :     // struct if needed.
      44           0 : }
      45             : 
      46        3126 : double CompareFunc( const Compare::Cell& rCell1, const Compare::Cell& rCell2, bool bIgnoreCase, CompareOptions* pOptions )
      47             : {
      48             :     // Keep DoubleError if encountered
      49             :     // #i40539# if bEmpty is set, bVal/nVal are uninitialized
      50        3126 :     if (!rCell1.mbEmpty && rCell1.mbValue && !rtl::math::isFinite(rCell1.mfValue))
      51           0 :         return rCell1.mfValue;
      52        3126 :     if (!rCell2.mbEmpty && rCell2.mbValue && !rtl::math::isFinite(rCell2.mfValue))
      53           0 :         return rCell2.mfValue;
      54             : 
      55        3126 :     size_t nStringQuery = 0;    // 0:=no, 1:=0, 2:=1
      56        3126 :     double fRes = 0;
      57        3126 :     if (rCell1.mbEmpty)
      58             :     {
      59          16 :         if (rCell2.mbEmpty)
      60             :             ;       // empty cell == empty cell, fRes 0
      61          16 :         else if (rCell2.mbValue)
      62             :         {
      63           8 :             if (rCell2.mfValue != 0.0)
      64             :             {
      65           2 :                 if (rCell2.mfValue < 0.0)
      66           0 :                     fRes = 1;       // empty cell > -x
      67             :                 else
      68           2 :                     fRes = -1;      // empty cell < x
      69             :             }
      70             :             // else: empty cell == 0.0
      71             :         }
      72             :         else
      73             :         {
      74           8 :             if (!rCell2.maStr.isEmpty())
      75           8 :                 fRes = -1;      // empty cell < "..."
      76             :             // else: empty cell == ""
      77             :         }
      78             :     }
      79        3110 :     else if (rCell2.mbEmpty)
      80             :     {
      81           0 :         if (rCell1.mbValue)
      82             :         {
      83           0 :             if (rCell1.mfValue != 0.0)
      84             :             {
      85           0 :                 if (rCell1.mfValue < 0.0)
      86           0 :                     fRes = -1;      // -x < empty cell
      87             :                 else
      88           0 :                     fRes = 1;       // x > empty cell
      89             :             }
      90             :             // else: empty cell == 0.0
      91             :         }
      92             :         else
      93             :         {
      94           0 :             if (!rCell1.maStr.isEmpty())
      95           0 :                 fRes = 1;       // "..." > empty cell
      96             :             // else: "" == empty cell
      97             :         }
      98             :     }
      99        3110 :     else if (rCell1.mbValue)
     100             :     {
     101        3072 :         if (rCell2.mbValue)
     102             :         {
     103        3060 :             if (!rtl::math::approxEqual(rCell1.mfValue, rCell2.mfValue))
     104             :             {
     105         112 :                 if (rCell1.mfValue - rCell2.mfValue < 0)
     106          82 :                     fRes = -1;
     107             :                 else
     108          30 :                     fRes = 1;
     109             :             }
     110             :         }
     111             :         else
     112             :         {
     113          12 :             fRes = -1;          // number is less than string
     114          12 :             nStringQuery = 2;   // 1+1
     115             :         }
     116             :     }
     117          38 :     else if (rCell2.mbValue)
     118             :     {
     119          14 :         fRes = 1;               // string is greater than number
     120          14 :         nStringQuery = 1;       // 0+1
     121             :     }
     122             :     else
     123             :     {
     124             :         // Both strings.
     125          24 :         if (pOptions)
     126             :         {
     127             :             // All similar to ScTable::ValidQuery(), *rComp.pVal[1] actually
     128             :             // is/must be identical to *rEntry.pStr, which is essential for
     129             :             // regex to work through GetSearchTextPtr().
     130           0 :             ScQueryEntry& rEntry = pOptions->aQueryEntry;
     131             :             OSL_ENSURE(rEntry.GetQueryItem().maString == rCell2.maStr, "ScInterpreter::CompareFunc: broken options");
     132           0 :             if (pOptions->bRegEx)
     133             :             {
     134           0 :                 sal_Int32 nStart = 0;
     135           0 :                 sal_Int32 nStop  = rCell1.maStr.getLength();
     136             :                 bool bMatch = rEntry.GetSearchTextPtr(
     137           0 :                         !bIgnoreCase)->SearchForward(
     138           0 :                             rCell1.maStr.getString(), &nStart, &nStop);
     139           0 :                 if (bMatch && pOptions->bMatchWholeCell && (nStart != 0 || nStop != rCell1.maStr.getLength()))
     140           0 :                     bMatch = false;     // RegEx must match entire string.
     141           0 :                 fRes = (bMatch ? 0 : 1);
     142             :             }
     143           0 :             else if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
     144             :             {
     145             :                 ::utl::TransliterationWrapper* pTransliteration =
     146             :                     (bIgnoreCase ? ScGlobal::GetpTransliteration() :
     147           0 :                      ScGlobal::GetCaseTransliteration());
     148           0 :                 bool bMatch = false;
     149           0 :                 if (pOptions->bMatchWholeCell)
     150             :                 {
     151           0 :                     if (bIgnoreCase)
     152           0 :                         bMatch = rCell1.maStr.getDataIgnoreCase() == rCell2.maStr.getDataIgnoreCase();
     153             :                     else
     154           0 :                         bMatch = rCell1.maStr.getData() == rCell2.maStr.getData();
     155             :                 }
     156             :                 else
     157             :                 {
     158             :                     OUString aCell( pTransliteration->transliterate(
     159             :                                 rCell1.maStr.getString(), ScGlobal::eLnge, 0,
     160           0 :                                 rCell1.maStr.getLength(), NULL));
     161             :                     OUString aQuer( pTransliteration->transliterate(
     162             :                                 rCell2.maStr.getString(), ScGlobal::eLnge, 0,
     163           0 :                                 rCell2.maStr.getLength(), NULL));
     164           0 :                     bMatch = (aCell.indexOf( aQuer ) != -1);
     165             :                 }
     166           0 :                 fRes = (bMatch ? 0 : 1);
     167             :             }
     168           0 :             else if (bIgnoreCase)
     169             :                 fRes = (double) ScGlobal::GetCollator()->compareString(
     170           0 :                         rCell1.maStr.getString(), rCell2.maStr.getString());
     171             :             else
     172             :                 fRes = (double) ScGlobal::GetCaseCollator()->compareString(
     173           0 :                         rCell1.maStr.getString(), rCell2.maStr.getString());
     174             :         }
     175          24 :         else if (bIgnoreCase)
     176             :             fRes = (double) ScGlobal::GetCollator()->compareString(
     177           0 :                 rCell1.maStr.getString(), rCell2.maStr.getString());
     178             :         else
     179             :             fRes = (double) ScGlobal::GetCaseCollator()->compareString(
     180          24 :                 rCell1.maStr.getString(), rCell2.maStr.getString());
     181             :     }
     182             : 
     183        3126 :     if (nStringQuery && pOptions)
     184             :     {
     185           0 :         const ScQueryEntry& rEntry = pOptions->aQueryEntry;
     186           0 :         const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
     187           0 :         if (!rItems.empty())
     188             :         {
     189           0 :             const ScQueryEntry::Item& rItem = rItems[0];
     190           0 :             if (rItem.meType != ScQueryEntry::ByString && !rItem.maString.isEmpty() &&
     191           0 :                 (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL))
     192             :             {
     193             :                 // As in ScTable::ValidQuery() match a numeric string for a
     194             :                 // number query that originated from a string, e.g. in SUMIF
     195             :                 // and COUNTIF. Transliteration is not needed here.
     196           0 :                 bool bEqual = false;
     197           0 :                 if (nStringQuery == 1)
     198           0 :                     bEqual = rCell1.maStr == rItem.maString;
     199             :                 else
     200           0 :                     bEqual = rCell2.maStr == rItem.maString;
     201             : 
     202             :                 // match => fRes=0, else fRes=1
     203           0 :                 fRes = double((rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual);
     204             :             }
     205             :         }
     206             :     }
     207             : 
     208        3126 :     return fRes;
     209             : }
     210             : 
     211           0 : double CompareFunc( const Compare::Cell& rCell1, double fCell2, CompareOptions* pOptions )
     212             : {
     213             :     // Keep DoubleError if encountered
     214             :     // #i40539# if bEmpty is set, bVal/nVal are uninitialized
     215           0 :     if (!rCell1.mbEmpty && rCell1.mbValue && !rtl::math::isFinite(rCell1.mfValue))
     216           0 :         return rCell1.mfValue;
     217           0 :     if (!rtl::math::isFinite(fCell2))
     218           0 :         return fCell2;
     219             : 
     220           0 :     bool bStringQuery = false;
     221           0 :     double fRes = 0;
     222           0 :     if (rCell1.mbEmpty)
     223             :     {
     224           0 :         if (fCell2 != 0.0)
     225             :         {
     226           0 :             if (fCell2 < 0.0)
     227           0 :                 fRes = 1;       // empty cell > -x
     228             :             else
     229           0 :                 fRes = -1;      // empty cell < x
     230             :         }
     231             :         // else: empty cell == 0.0
     232             :     }
     233           0 :     else if (rCell1.mbValue)
     234             :     {
     235           0 :         if (!rtl::math::approxEqual(rCell1.mfValue, fCell2))
     236             :         {
     237           0 :             if (rCell1.mfValue - fCell2 < 0)
     238           0 :                 fRes = -1;
     239             :             else
     240           0 :                 fRes = 1;
     241             :         }
     242             :     }
     243             :     else
     244             :     {
     245           0 :         fRes = 1;               // string is greater than number
     246           0 :         bStringQuery = true;
     247             :     }
     248             : 
     249           0 :     if (bStringQuery && pOptions)
     250             :     {
     251           0 :         const ScQueryEntry& rEntry = pOptions->aQueryEntry;
     252           0 :         const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
     253           0 :         if (!rItems.empty())
     254             :         {
     255           0 :             const ScQueryEntry::Item& rItem = rItems[0];
     256           0 :             if (rItem.meType != ScQueryEntry::ByString && !rItem.maString.isEmpty() &&
     257           0 :                 (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL))
     258             :             {
     259             :                 // As in ScTable::ValidQuery() match a numeric string for a
     260             :                 // number query that originated from a string, e.g. in SUMIF
     261             :                 // and COUNTIF. Transliteration is not needed here.
     262           0 :                 bool bEqual = rCell1.maStr == rItem.maString;
     263             : 
     264             :                 // match => fRes=0, else fRes=1
     265           0 :                 fRes = double((rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual);
     266             :             }
     267             :         }
     268             :     }
     269             : 
     270           0 :     return fRes;
     271             : }
     272             : 
     273           0 : double CompareFunc( double fCell1, double fCell2 )
     274             : {
     275             :     // Keep DoubleError if encountered
     276             :     // #i40539# if bEmpty is set, bVal/nVal are uninitialized
     277           0 :     if (!rtl::math::isFinite(fCell1))
     278           0 :         return fCell1;
     279           0 :     if (!rtl::math::isFinite(fCell2))
     280           0 :         return fCell2;
     281             : 
     282           0 :     double fRes = 0.0;
     283             : 
     284           0 :     if (!rtl::math::approxEqual(fCell1, fCell2))
     285             :     {
     286           0 :         if (fCell1 - fCell2 < 0.0)
     287           0 :             fRes = -1;
     288             :         else
     289           0 :             fRes = 1;
     290             :     }
     291             : 
     292           0 :     return fRes;
     293             : }
     294             : 
     295           0 : double CompareEmptyToNumericFunc( double fCell2 )
     296             : {
     297             :     // Keep DoubleError if encountered
     298             :     // #i40539# if bEmpty is set, bVal/nVal are uninitialized
     299           0 :     if (!rtl::math::isFinite(fCell2))
     300           0 :         return fCell2;
     301             : 
     302           0 :     double fRes = 0;
     303           0 :     if (fCell2 != 0.0)
     304             :     {
     305           0 :         if (fCell2 < 0.0)
     306           0 :             fRes = 1;       // empty cell > -x
     307             :         else
     308           0 :             fRes = -1;      // empty cell < x
     309             :     }
     310             :     // else: empty cell == 0.0
     311             : 
     312           0 :     return fRes;
     313             : }
     314             : 
     315         228 : }
     316             : 
     317             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10