LibreOffice Module sc (master) 1
reffind.cxx
Go to the documentation of this file.
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 <sal/config.h>
21
23
24#include <reffind.hxx>
25#include <global.hxx>
26#include <compiler.hxx>
27#include <document.hxx>
28#include <utility>
29
30namespace {
31
32// Include colon; addresses in range reference are handled individually.
33const sal_Unicode pDelimiters[] = {
34 '=','(',')','+','-','*','/','^','&',' ','{','}','<','>',':', 0
35};
36
37bool IsText( sal_Unicode c )
38{
39 bool bFound = ScGlobal::UnicodeStrChr( pDelimiters, c );
40 if (bFound)
41 // This is one of delimiters, therefore not text.
42 return false;
43
44 // argument separator is configurable.
46 return c != sep;
47}
48
49bool IsText( bool& bQuote, sal_Unicode c )
50{
51 if (c == '\'')
52 {
53 bQuote = !bQuote;
54 return true;
55 }
56 if (bQuote)
57 return true;
58
59 return IsText(c);
60}
61
67sal_Int32 FindStartPos(const sal_Unicode* p, sal_Int32 nStartPos, sal_Int32 nEndPos)
68{
69 while (nStartPos <= nEndPos && !IsText(p[nStartPos]))
70 ++nStartPos;
71
72 return nStartPos;
73}
74
75sal_Int32 FindEndPosA1(const sal_Unicode* p, sal_Int32 nStartPos, sal_Int32 nEndPos)
76{
77 bool bQuote = false;
78 sal_Int32 nNewEnd = nStartPos;
79 while (nNewEnd <= nEndPos && IsText(bQuote, p[nNewEnd]))
80 ++nNewEnd;
81
82 return nNewEnd;
83}
84
85sal_Int32 FindEndPosR1C1(const sal_Unicode* p, sal_Int32 nStartPos, sal_Int32 nEndPos)
86{
87 sal_Int32 nNewEnd = nStartPos;
88 p = &p[nStartPos];
89 for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
90 {
91 if (*p == '\'')
92 {
93 // Skip until the closing quote.
94 for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
95 if (*p == '\'')
96 break;
97 if (nNewEnd > nEndPos)
98 break;
99 }
100 else if (*p == '[')
101 {
102 // Skip until the closing bracket.
103 for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
104 if (*p == ']')
105 break;
106 if (nNewEnd > nEndPos)
107 break;
108 }
109 else if (!IsText(*p))
110 break;
111 }
112
113 return nNewEnd;
114}
115
120sal_Int32 FindEndPos(const sal_Unicode* p, sal_Int32 nStartPos, sal_Int32 nEndPos,
122{
123 switch (eConv)
124 {
126 return FindEndPosR1C1(p, nStartPos, nEndPos);
129 default:
130 return FindEndPosA1(p, nStartPos, nEndPos);
131 }
132}
133
134void ExpandToTextA1(const sal_Unicode* p, sal_Int32 nLen, sal_Int32& rStartPos, sal_Int32& rEndPos)
135{
136 bool bQuote = false; // skip quoted text
137 while (rStartPos > 0 && IsText(bQuote, p[rStartPos - 1]) )
138 --rStartPos;
139 if (rEndPos)
140 --rEndPos;
141 while (rEndPos+1 < nLen && IsText(p[rEndPos + 1]) )
142 ++rEndPos;
143}
144
145void ExpandToTextR1C1(const sal_Unicode* p, sal_Int32 nLen, sal_Int32& rStartPos, sal_Int32& rEndPos)
146{
147 // move back the start position to the first text character.
148 if (rStartPos > 0)
149 {
150 for (--rStartPos; rStartPos > 0; --rStartPos)
151 {
152 sal_Unicode c = p[rStartPos];
153 if (c == '\'')
154 {
155 // Skip until the opening quote.
156 for (--rStartPos; rStartPos > 0; --rStartPos)
157 {
158 c = p[rStartPos];
159 if (c == '\'')
160 break;
161 }
162 if (rStartPos == 0)
163 break;
164 }
165 else if (c == ']')
166 {
167 // Skip until the opening bracket.
168 for (--rStartPos; rStartPos > 0; --rStartPos)
169 {
170 c = p[rStartPos];
171 if (c == '[')
172 break;
173 }
174 if (rStartPos == 0)
175 break;
176 }
177 else if (!IsText(c))
178 {
179 ++rStartPos;
180 break;
181 }
182 }
183 }
184
185 // move forward the end position to the last text character.
186 rEndPos = FindEndPosR1C1(p, rEndPos, nLen-1);
187}
188
189void ExpandToText(const sal_Unicode* p, sal_Int32 nLen, sal_Int32& rStartPos, sal_Int32& rEndPos,
191{
192 switch (eConv)
193 {
195 ExpandToTextR1C1(p, nLen, rStartPos, rEndPos);
196 break;
199 default:
200 ExpandToTextA1(p, nLen, rStartPos, rEndPos);
201 }
202}
203
204}
205
207 OUString aFormula, const ScAddress& rPos,
209 maFormula(std::move(aFormula)),
210 meConv(eConvP),
211 mrDoc(rDoc),
212 maPos(rPos),
213 mnFound(0),
214 mnSelStart(0),
215 mnSelEnd(0)
216{
217}
218
220{
221}
222
224{
226 ScRefFlags nNew = nOld & Mask_ABS;
227 nNew = ScRefFlags( o3tl::to_underlying(nNew) - 1 ) & Mask_ABS; // weiterzaehlen
228
229 if (!(nOld & ScRefFlags::TAB_3D))
230 nNew &= ~ScRefFlags::TAB_ABS; // not 3D -> never absolute!
231
232 return (nOld & ~Mask_ABS) | nNew;
233}
234
235void ScRefFinder::ToggleRel( sal_Int32 nStartPos, sal_Int32 nEndPos )
236{
237 sal_Int32 nLen = maFormula.getLength();
238 if (nLen <= 0)
239 return;
240 const sal_Unicode* pSource = maFormula.getStr(); // for quick access
241
242 // expand selection, and instead of selection start- and end-index
243
244 if ( nEndPos < nStartPos )
245 ::std::swap(nEndPos, nStartPos);
246
247 ExpandToText(pSource, nLen, nStartPos, nEndPos, meConv);
248
249 OUStringBuffer aResult;
250 OUString aExpr;
251 OUString aSep;
252 ScAddress aAddr;
253 mnFound = 0;
254
255 sal_Int32 nLoopStart = nStartPos;
256 while ( nLoopStart <= nEndPos )
257 {
258 // Determine the start and end positions of a text segment. Note that
259 // the end position returned from FindEndPos may be one position after
260 // the last character position in case of the last segment.
261 sal_Int32 nEStart = FindStartPos(pSource, nLoopStart, nEndPos);
262 sal_Int32 nEEnd = FindEndPos(pSource, nEStart, nEndPos, meConv);
263
264 aSep = maFormula.copy(nLoopStart, nEStart-nLoopStart);
265 if (nEEnd < maFormula.getLength())
266 aExpr = maFormula.copy(nEStart, nEEnd-nEStart);
267 else
268 aExpr = maFormula.copy(nEStart);
269
270 // Check the validity of the expression, and toggle the relative flag.
271 ScAddress::Details aDetails(meConv, maPos.Row(), maPos.Col());
273 ScRefFlags nResult = aAddr.Parse(aExpr, mrDoc, aDetails, &aExtInfo);
274 if ( nResult & ScRefFlags::VALID )
275 {
276 ScRefFlags nFlags;
277 if( aExtInfo.mbExternal )
278 { // retain external doc name and tab name before toggle relative flag
279 sal_Int32 nSep;
280 switch(meConv)
281 {
285 nSep = aExpr.lastIndexOf('!');
286 break;
288 default:
289 nSep = aExpr.lastIndexOf('.');
290 break;
291 }
292 if (nSep >= 0)
293 {
294 OUString aRef = aExpr.copy(nSep+1);
295 std::u16string_view aExtDocNameTabName = aExpr.subView(0, nSep+1);
296 nResult = aAddr.Parse(aRef, mrDoc, aDetails);
297 aAddr.SetTab(0); // force to first tab to avoid error on checking
298 nFlags = lcl_NextFlags( nResult );
299 aExpr = aExtDocNameTabName + aAddr.Format(nFlags, &mrDoc, aDetails);
300 }
301 else
302 {
303 assert(!"Invalid syntax according to address convention.");
304 }
305 }
306 else
307 {
308 nFlags = lcl_NextFlags( nResult );
309 aExpr = aAddr.Format(nFlags, &mrDoc, aDetails);
310 }
311
312 sal_Int32 nAbsStart = nStartPos+aResult.getLength()+aSep.getLength();
313
314 if (!mnFound) // first reference ?
315 mnSelStart = nAbsStart;
316 mnSelEnd = nAbsStart + aExpr.getLength(); // selection, no indices
317 ++mnFound;
318 }
319
320 // assemble
321
322 aResult.append(aSep);
323 aResult.append(aExpr);
324
325 nLoopStart = nEEnd;
326 }
327
328 OUString aTotal = maFormula.subView(0, nStartPos) + aResult;
329 if (nEndPos < maFormula.getLength()-1)
330 aTotal += maFormula.subView(nEndPos+1);
331
332 maFormula = aTotal;
333}
334
335/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScRefFlags
Definition: address.hxx:158
OUString maFormula
SC_DLLPUBLIC void Format(OStringBuffer &r, ScRefFlags nFlags, const ScDocument *pDocument=nullptr, const Details &rDetails=detailsOOOa1) const
Definition: address.cxx:2074
SC_DLLPUBLIC ScRefFlags Parse(const OUString &, const ScDocument &, const Details &rDetails=detailsOOOa1, ExternalInfo *pExtInfo=nullptr, const css::uno::Sequence< css::sheet::ExternalLinkInfo > *pExternalLinks=nullptr, sal_Int32 *pSheetEndPos=nullptr, const OUString *pErrRef=nullptr)
Definition: address.cxx:1537
SCROW Row() const
Definition: address.hxx:274
void SetTab(SCTAB nTabP)
Definition: address.hxx:295
SCCOL Col() const
Definition: address.hxx:279
static const sal_Unicode * UnicodeStrChr(const sal_Unicode *pStr, sal_Unicode c)
strchr() functionality on unicode, as long as we need it for FormulaToken etc.
Definition: global.cxx:689
ScRefFinder(OUString aFormula, const ScAddress &rPos, ScDocument &rDoc, formula::FormulaGrammar::AddressConvention eConvP=formula::FormulaGrammar::CONV_OOO)
Definition: reffind.cxx:206
ScAddress maPos
Definition: reffind.hxx:31
void ToggleRel(sal_Int32 nStartPos, sal_Int32 nEndPos)
Definition: reffind.cxx:235
ScDocument & mrDoc
Definition: reffind.hxx:30
formula::FormulaGrammar::AddressConvention meConv
Definition: reffind.hxx:29
OUString maFormula
Definition: reffind.hxx:28
sal_Int32 mnSelEnd
Definition: reffind.hxx:34
sal_Int32 mnSelStart
Definition: reffind.hxx:33
sal_Int32 mnFound
Definition: reffind.hxx:32
static sal_Unicode GetNativeSymbolChar(OpCode eOp)
void * p
constexpr std::underlying_type_t< T > to_underlying(T e)
static ScRefFlags lcl_NextFlags(ScRefFlags nOld)
Definition: reffind.cxx:223
sal_uInt16 sal_Unicode