[Libreoffice-commits] core.git: sc/inc sc/source

Eike Rathke erack at redhat.com
Sat May 14 00:23:47 UTC 2016


 sc/inc/address.hxx              |    4 -
 sc/source/core/tool/address.cxx |  145 ++++++++++++++++++++++++----------------
 2 files changed, 91 insertions(+), 58 deletions(-)

New commits:
commit 442387bdf493aa6a752fd2531507625dc9e5a4fc
Author: Eike Rathke <erack at redhat.com>
Date:   Sat May 14 02:14:02 2016 +0200

    recognize #REF! particles of invalidated references, tdf#86575 follow-up
    
    ... also in OOXML where they were wrongly written so upon next save
    they'd become a single #REF! as Excel expects.
    
    Also for Excel A1 UI notation.
    
    Change-Id: I5039d941f003bd4bed762c0e8cd754c23f1c8aa7

diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index f02f064..9fff5a3 100644
--- a/sc/inc/address.hxx
+++ b/sc/inc/address.hxx
@@ -526,6 +526,7 @@ public:
         @param pExternalLinks  pointer to ExternalLinkInfo sequence, may be
             NULL for non-filter usage, in which case indices such as [1] are
             not resolved.
+        @param pErrRef  pointer to "#REF!" string if to be accepted.
         @returns
             Pointer to the position after '!' if successfully parsed, and
             rExternDocName, rStartTabName and/or rEndTabName filled if
@@ -539,7 +540,8 @@ public:
                                         OUString& rExternDocName, OUString& rStartTabName,
                                         OUString& rEndTabName, ScRefFlags& nFlags,
                                         bool bOnlyAcceptSingle,
-                                        const css::uno::Sequence<css::sheet::ExternalLinkInfo>* pExternalLinks = nullptr );
+                                        const css::uno::Sequence<css::sheet::ExternalLinkInfo>* pExternalLinks = nullptr,
+                                        const OUString* pErrRef = nullptr );
 
     SC_DLLPUBLIC OUString Format(ScRefFlags nFlags = ScRefFlags::ZERO, const ScDocument* pDocument = nullptr,
                                  const ScAddress::Details& rDetails = ScAddress::detailsOOOa1) const;
diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx
index e0d4b0c..265877c 100644
--- a/sc/source/core/tool/address.cxx
+++ b/sc/source/core/tool/address.cxx
@@ -168,6 +168,38 @@ static const sal_Unicode* lcl_eatWhiteSpace( const sal_Unicode* p )
     return p;
 }
 
+// Compare ignore case ASCII.
+static bool lcl_isString( const sal_Unicode* p1, const OUString& rStr )
+{
+    const size_t n = rStr.getLength();
+    if (!n)
+        return false;
+    const sal_Unicode* p2 = rStr.getStr();
+    for (size_t i=0; i<n; ++i)
+    {
+        if (!p1[i])
+            return false;
+        if (p1[i] != p2[i])
+        {
+            sal_Unicode c1 = p1[i];
+            if ('A' <= c1 && c1 <= 'Z')
+                c1 += 0x20;
+            if (c1 < 'a' || 'z' < c1)
+                return false;   // not a letter
+
+            sal_Unicode c2 = p2[i];
+            if ('A' <= c2 && c2 <= 'Z')
+                c2 += 0x20;
+            if (c2 < 'a' || 'z' < c2)
+                return false;   // not a letter to match
+
+            if (c1 != c2)
+                return false;   // lower case doesn't match either
+        }
+    }
+    return true;
+}
+
 /** Determines the number of sheets an external reference spans and sets
     rRange.aEnd.nTab accordingly. If a sheet is not found, the corresponding
     bits in rFlags are cleared. pExtInfo is filled if it wasn't already. If in
@@ -258,7 +290,8 @@ static bool lcl_ScRange_External_TabSpan(
 static const sal_Unicode * lcl_XL_ParseSheetRef( const sal_Unicode* start,
                                                  OUString& rExternTabName,
                                                  bool bAllow3D,
-                                                 const sal_Unicode* pMsoxlQuoteStop )
+                                                 const sal_Unicode* pMsoxlQuoteStop,
+                                                 const OUString* pErrRef )
 {
     OUString aTabName;
     const sal_Unicode *p = start;
@@ -301,6 +334,12 @@ static const sal_Unicode * lcl_XL_ParseSheetRef( const sal_Unicode* start,
         if (aTabName.isEmpty())
             return nullptr;
     }
+    else if (pErrRef && lcl_isString( p, *pErrRef) && p[pErrRef->getLength()] == '!')
+    {
+        p += pErrRef->getLength();  // position after "#REF!" on '!'
+        // XXX NOTE: caller has to check the name and that it wasn't quoted.
+        aTabName = *pErrRef;
+    }
     else
     {
         bool only_digits = true;
@@ -435,7 +474,8 @@ const sal_Unicode* ScRange::Parse_XL_Header(
                                 OUString& rEndTabName,
                                 ScRefFlags& nFlags,
                                 bool bOnlyAcceptSingle,
-                                const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks )
+                                const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks,
+                                const OUString* pErrRef )
 {
     const sal_Unicode* startTabs, *start = p;
     ScRefFlags nSaveFlags = nFlags;
@@ -528,17 +568,19 @@ const sal_Unicode* ScRange::Parse_XL_Header(
     }
 
     startTabs = p;
-    p = lcl_XL_ParseSheetRef( p, rStartTabName, !bOnlyAcceptSingle, pMsoxlQuoteStop);
+    p = lcl_XL_ParseSheetRef( p, rStartTabName, !bOnlyAcceptSingle, pMsoxlQuoteStop, pErrRef);
     if( nullptr == p )
         return start;       // invalid tab
     if (bOnlyAcceptSingle && *p == ':')
         return nullptr;        // 3D
+    const sal_Unicode* startEndTabs = nullptr;
     if( p != startTabs )
     {
         nFlags |= ScRefFlags::TAB_VALID | ScRefFlags::TAB_3D | ScRefFlags::TAB_ABS;
         if( *p == ':' ) // 3d ref
         {
-            p = lcl_XL_ParseSheetRef( p+1, rEndTabName, false, pMsoxlQuoteStop);
+            startEndTabs = p + 1;
+            p = lcl_XL_ParseSheetRef( startEndTabs, rEndTabName, false, pMsoxlQuoteStop, pErrRef);
             if( p == nullptr )
             {
                 nFlags = nSaveFlags;
@@ -583,7 +625,7 @@ const sal_Unicode* ScRange::Parse_XL_Header(
         }
 
         SCTAB nTab;
-        if (!pDoc->GetTable(rStartTabName, nTab))
+        if ((pErrRef && *startTabs != '\'' && rStartTabName == *pErrRef) || !pDoc->GetTable(rStartTabName, nTab))
         {
             // invalid table name.
             nFlags &= ~ScRefFlags::TAB_VALID;
@@ -595,7 +637,8 @@ const sal_Unicode* ScRange::Parse_XL_Header(
 
         if (!rEndTabName.isEmpty())
         {
-            if (!pDoc->GetTable(rEndTabName, nTab))
+            if ((pErrRef && startEndTabs && *startEndTabs != '\'' && rEndTabName == *pErrRef) ||
+                    !pDoc->GetTable(rEndTabName, nTab))
             {
                 // invalid table name.
                 nFlags &= ~ScRefFlags::TAB2_VALID;
@@ -847,7 +890,8 @@ static ScRefFlags lcl_ScRange_Parse_XL_R1C1( ScRange& r,
 
 static inline const sal_Unicode* lcl_a1_get_col( const sal_Unicode* p,
                                                  ScAddress* pAddr,
-                                                 ScRefFlags* nFlags )
+                                                 ScRefFlags* nFlags,
+                                                 const OUString* pErrRef )
 {
     SCCOL nCol;
 
@@ -857,6 +901,14 @@ static inline const sal_Unicode* lcl_a1_get_col( const sal_Unicode* p,
         p++;
     }
 
+    if (pErrRef && lcl_isString( p, *pErrRef))
+    {
+        p += pErrRef->getLength();
+        *nFlags &= ~ScRefFlags::COL_VALID;
+        pAddr->SetCol(-1);
+        return p;
+    }
+
     if( !rtl::isAsciiAlpha( *p ) )
         return nullptr;
 
@@ -874,7 +926,8 @@ static inline const sal_Unicode* lcl_a1_get_col( const sal_Unicode* p,
 
 static inline const sal_Unicode* lcl_a1_get_row( const sal_Unicode* p,
                                                  ScAddress* pAddr,
-                                                 ScRefFlags* nFlags )
+                                                 ScRefFlags* nFlags,
+                                                 const OUString* pErrRef )
 {
     const sal_Unicode *pEnd;
     long int n;
@@ -885,6 +938,14 @@ static inline const sal_Unicode* lcl_a1_get_row( const sal_Unicode* p,
         p++;
     }
 
+    if (pErrRef && lcl_isString( p, *pErrRef))
+    {
+        p += pErrRef->getLength();
+        *nFlags &= ~ScRefFlags::ROW_VALID;
+        pAddr->SetRow(-1);
+        return p;
+    }
+
     n = sal_Unicode_strtol( p, &pEnd ) - 1;
     if( nullptr == pEnd || p == pEnd || n < 0 || n > MAXROW )
         return nullptr;
@@ -909,7 +970,8 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
                                            bool bOnlyAcceptSingle,
                                            ScAddress::ExternalInfo* pExtInfo,
                                            const uno::Sequence<sheet::ExternalLinkInfo>* pExternalLinks,
-                                           sal_Int32* pSheetEndPos )
+                                           sal_Int32* pSheetEndPos,
+                                           const OUString* pErrRef )
 {
     const sal_Unicode* const pStart = p;
     if (pSheetEndPos)
@@ -919,7 +981,7 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
     ScRefFlags nFlags = ScRefFlags::VALID | ScRefFlags::TAB_VALID, nFlags2 = ScRefFlags::TAB_VALID;
 
     p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName,
-            aEndTabName, nFlags, bOnlyAcceptSingle, pExternalLinks );
+            aEndTabName, nFlags, bOnlyAcceptSingle, pExternalLinks, pErrRef );
 
     ScRefFlags nBailOutFlags = ScRefFlags::ZERO;
     if (pSheetEndPos && pStart < p && (nFlags & ScRefFlags::TAB_VALID) && (nFlags & ScRefFlags::TAB_3D))
@@ -935,20 +997,20 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
     if( nullptr == p )
         return nBailOutFlags;
 
-    tmp1 = lcl_a1_get_col( p, &r.aStart, &nFlags );
+    tmp1 = lcl_a1_get_col( p, &r.aStart, &nFlags, pErrRef);
     if( tmp1 == nullptr )          // Is it a row only reference 3:5
     {
         if( bOnlyAcceptSingle ) // by definition full row refs are ranges
             return nBailOutFlags;
 
-        tmp1 = lcl_a1_get_row( p, &r.aStart, &nFlags );
+        tmp1 = lcl_a1_get_row( p, &r.aStart, &nFlags, pErrRef);
 
         tmp1 = lcl_eatWhiteSpace( tmp1 );
         if( !tmp1 || *tmp1++ != ':' ) // Even a singleton requires ':' (eg 2:2)
             return nBailOutFlags;
 
         tmp1 = lcl_eatWhiteSpace( tmp1 );
-        tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 );
+        tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2, pErrRef);
         if( !tmp2 || *tmp2 != 0 )   // Must have fully parsed a singleton.
             return nBailOutFlags;
 
@@ -960,7 +1022,7 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
         return nFlags;
     }
 
-    tmp2 = lcl_a1_get_row( tmp1, &r.aStart, &nFlags );
+    tmp2 = lcl_a1_get_row( tmp1, &r.aStart, &nFlags, pErrRef);
     if( tmp2 == nullptr )          // check for col only reference F:H
     {
         if( bOnlyAcceptSingle ) // by definition full col refs are ranges
@@ -971,7 +1033,7 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
             return nBailOutFlags;
 
         tmp1 = lcl_eatWhiteSpace( tmp1 );
-        tmp2 = lcl_a1_get_col( tmp1, &r.aEnd, &nFlags2 );
+        tmp2 = lcl_a1_get_col( tmp1, &r.aEnd, &nFlags2, pErrRef);
         if( !tmp2 || *tmp2 != 0 )   // Must have fully parsed a singleton.
             return nBailOutFlags;
 
@@ -1020,10 +1082,10 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
 
     p = tmp2;
     p = lcl_eatWhiteSpace( p+1 );   // after ':'
-    tmp1 = lcl_a1_get_col( p, &r.aEnd, &nFlags2 );
+    tmp1 = lcl_a1_get_col( p, &r.aEnd, &nFlags2, pErrRef);
     if( !tmp1 && aEndTabName.isEmpty() )     // Probably the aEndTabName was specified after the first range
     {
-        p = lcl_XL_ParseSheetRef( p, aEndTabName, false, nullptr );
+        p = lcl_XL_ParseSheetRef( p, aEndTabName, false, nullptr, pErrRef);
         if( p )
         {
             SCTAB nTab = 0;
@@ -1034,13 +1096,13 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
             }
             if (*p == '!' || *p == ':')
                 p = lcl_eatWhiteSpace( p+1 );
-            tmp1 = lcl_a1_get_col( p, &r.aEnd, &nFlags2 );
+            tmp1 = lcl_a1_get_col( p, &r.aEnd, &nFlags2, pErrRef);
         }
     }
     if( !tmp1 ) // strange, but maybe valid singleton
         return isValidSingleton( nFlags, nFlags2) ? nFlags : (nFlags & ~ScRefFlags::VALID);
 
-    tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 );
+    tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2, pErrRef);
     if( !tmp2 ) // strange, but maybe valid singleton
         return isValidSingleton( nFlags, nFlags2) ? nFlags : (nFlags & ~ScRefFlags::VALID);
 
@@ -1056,38 +1118,6 @@ static ScRefFlags lcl_ScRange_Parse_XL_A1( ScRange& r,
     return nFlags;
 }
 
-// Compare ignore case ASCII.
-static bool lcl_isString( const sal_Unicode* p1, const OUString& rStr )
-{
-    const size_t n = rStr.getLength();
-    if (!n)
-        return false;
-    const sal_Unicode* p2 = rStr.getStr();
-    for (size_t i=0; i<n; ++i)
-    {
-        if (!p1[i])
-            return false;
-        if (p1[i] != p2[i])
-        {
-            sal_Unicode c1 = p1[i];
-            if ('A' <= c1 && c1 <= 'Z')
-                c1 += 0x20;
-            if (c1 < 'a' || 'z' < c1)
-                return false;   // not a letter
-
-            sal_Unicode c2 = p2[i];
-            if ('A' <= c2 && c2 <= 'Z')
-                c2 += 0x20;
-            if (c2 < 'a' || 'z' < c2)
-                return false;   // not a letter to match
-
-            if (c1 != c2)
-                return false;   // lower case doesn't match either
-        }
-    }
-    return true;
-}
-
 /**
     @param p        pointer to null-terminated sal_Unicode string
     @param rRawRes  returns ScRefFlags::... flags without the final check for full
@@ -1432,7 +1462,7 @@ static ScRefFlags lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc,
             ScRefFlags nFlags = lcl_ScRange_Parse_XL_A1(
                     rRange, p, pDoc, true, pExtInfo,
                     (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : nullptr),
-                    pSheetEndPos);
+                    pSheetEndPos, pErrRef);
             rAddr = rRange.aStart;
             return nFlags;
         }
@@ -1709,7 +1739,8 @@ ScRefFlags ScRange::Parse( const OUString& rString, ScDocument* pDoc,
         case formula::FormulaGrammar::CONV_XL_OOX:
         {
             return lcl_ScRange_Parse_XL_A1( *this, rString.getStr(), pDoc, false, pExtInfo,
-                    (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : nullptr), nullptr );
+                    (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : nullptr),
+                    nullptr, pErrRef );
         }
 
         case formula::FormulaGrammar::CONV_XL_R1C1:
@@ -1761,11 +1792,11 @@ ScRefFlags ScRange::ParseCols( const OUString& rStr, ScDocument* pDoc,
     case formula::FormulaGrammar::CONV_OOO: // No full col refs in OOO yet, assume XL notation
     case formula::FormulaGrammar::CONV_XL_A1:
     case formula::FormulaGrammar::CONV_XL_OOX:
-        if (nullptr != (p = lcl_a1_get_col( p, &aStart, &ignored ) ) )
+        if (nullptr != (p = lcl_a1_get_col( p, &aStart, &ignored, nullptr) ) )
         {
             if( p[0] == ':')
             {
-                if( nullptr != (p = lcl_a1_get_col( p+1, &aEnd, &ignored )))
+                if( nullptr != (p = lcl_a1_get_col( p+1, &aEnd, &ignored, nullptr)))
                 {
                     nRes = ScRefFlags::COL_VALID;
                 }
@@ -1820,11 +1851,11 @@ void ScRange::ParseRows( const OUString& rStr, ScDocument* pDoc,
     case formula::FormulaGrammar::CONV_OOO: // No full row refs in OOO yet, assume XL notation
     case formula::FormulaGrammar::CONV_XL_A1:
     case formula::FormulaGrammar::CONV_XL_OOX:
-        if (nullptr != (p = lcl_a1_get_row( p, &aStart, &ignored ) ) )
+        if (nullptr != (p = lcl_a1_get_row( p, &aStart, &ignored, nullptr) ) )
         {
             if( p[0] == ':')
             {
-                if( nullptr != (p = lcl_a1_get_row( p+1, &aEnd, &ignored )))
+                if( nullptr != (p = lcl_a1_get_row( p+1, &aEnd, &ignored, nullptr)))
                 {
                 }
             }


More information about the Libreoffice-commits mailing list