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 <string.h>
21 :
22 : #include "reffind.hxx"
23 : #include "global.hxx"
24 : #include "compiler.hxx"
25 : #include "document.hxx"
26 :
27 : // STATIC DATA -----------------------------------------------------------
28 :
29 : namespace {
30 :
31 : // include colon -> duplicate referenced are handled individual
32 : const sal_Unicode pDelimiters[] = {
33 : '=','(',')','+','-','*','/','^','&',' ','{','}','<','>',':', 0
34 : };
35 :
36 : // =======================================================================
37 :
38 104 : inline bool IsText( sal_Unicode c )
39 : {
40 104 : bool bFound = ScGlobal::UnicodeStrChr( pDelimiters, c );
41 104 : if (bFound)
42 : // This is one of delimiters, therefore not text.
43 16 : return false;
44 :
45 : // argument separator is configurable.
46 88 : const sal_Unicode sep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
47 88 : return c != sep;
48 : }
49 :
50 40 : inline bool IsText( bool& bQuote, sal_Unicode c )
51 : {
52 40 : if (c == '\'')
53 : {
54 0 : bQuote = !bQuote;
55 0 : return true;
56 : }
57 40 : if (bQuote)
58 0 : return true;
59 :
60 40 : return IsText(c);
61 : }
62 :
63 : /**
64 : * Find first character position that is considered text. A character is
65 : * considered a text when it's within the ascii range and when it's not a
66 : * delimiter.
67 : */
68 16 : xub_StrLen FindStartPos(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos)
69 : {
70 48 : while (nStartPos <= nEndPos && !IsText(p[nStartPos]))
71 16 : ++nStartPos;
72 :
73 16 : return nStartPos;
74 : }
75 :
76 8 : xub_StrLen FindEndPosA1(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos)
77 : {
78 8 : bool bQuote = false;
79 8 : xub_StrLen nNewEnd = nStartPos;
80 56 : while (nNewEnd <= nEndPos && IsText(bQuote, p[nNewEnd]))
81 40 : ++nNewEnd;
82 :
83 8 : return nNewEnd;
84 : }
85 :
86 16 : xub_StrLen FindEndPosR1C1(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos)
87 : {
88 16 : xub_StrLen nNewEnd = nStartPos;
89 16 : p = &p[nStartPos];
90 56 : for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
91 : {
92 40 : if (*p == '\'')
93 : {
94 : // Skip until the closing quote.
95 0 : for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
96 0 : if (*p == '\'')
97 0 : break;
98 : }
99 40 : else if (*p == '[')
100 : {
101 : // Skip until the closing braket.
102 32 : for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
103 32 : if (*p == ']')
104 8 : break;
105 : }
106 32 : else if (!IsText(*p))
107 0 : break;
108 : }
109 :
110 16 : return nNewEnd;
111 : }
112 :
113 : /**
114 : * Find last character position that is considred text, from the specified
115 : * start position.
116 : */
117 16 : xub_StrLen FindEndPos(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos,
118 : formula::FormulaGrammar::AddressConvention eConv)
119 : {
120 16 : switch (eConv)
121 : {
122 : case formula::FormulaGrammar::CONV_XL_R1C1:
123 8 : return FindEndPosR1C1(p, nStartPos, nEndPos);
124 : case formula::FormulaGrammar::CONV_OOO:
125 : case formula::FormulaGrammar::CONV_XL_A1:
126 : default:
127 8 : return FindEndPosA1(p, nStartPos, nEndPos);
128 : }
129 : }
130 :
131 8 : void ExpandToTextA1(const sal_Unicode* p, xub_StrLen nLen, xub_StrLen& rStartPos, xub_StrLen& rEndPos)
132 : {
133 16 : while (rStartPos > 0 && IsText(p[rStartPos - 1]) )
134 0 : --rStartPos;
135 8 : if (rEndPos)
136 8 : --rEndPos;
137 16 : while (rEndPos+1 < nLen && IsText(p[rEndPos + 1]) )
138 0 : ++rEndPos;
139 8 : }
140 :
141 8 : void ExpandToTextR1C1(const sal_Unicode* p, xub_StrLen nLen, xub_StrLen& rStartPos, xub_StrLen& rEndPos)
142 : {
143 : // move back the start position to the first text character.
144 8 : if (rStartPos > 0)
145 : {
146 0 : for (--rStartPos; rStartPos > 0; --rStartPos)
147 : {
148 0 : sal_Unicode c = p[rStartPos];
149 0 : if (c == '\'')
150 : {
151 : // Skip until the opening quote.
152 0 : for (--rStartPos; rStartPos > 0; --rStartPos)
153 : {
154 0 : c = p[rStartPos];
155 0 : if (c == '\'')
156 0 : break;
157 : }
158 : }
159 0 : else if (c == ']')
160 : {
161 : // Skip until the opening braket.
162 0 : for (--rStartPos; rStartPos > 0; --rStartPos)
163 : {
164 0 : if (c == '[')
165 0 : break;
166 : }
167 : }
168 0 : else if (!IsText(c))
169 : {
170 0 : ++rStartPos;
171 0 : break;
172 : }
173 : }
174 : }
175 :
176 : // move forward the end position to the last text character.
177 8 : rEndPos = FindEndPosR1C1(p, rEndPos, nLen-1);
178 8 : }
179 :
180 16 : void ExpandToText(const sal_Unicode* p, xub_StrLen nLen, xub_StrLen& rStartPos, xub_StrLen& rEndPos,
181 : formula::FormulaGrammar::AddressConvention eConv)
182 : {
183 16 : switch (eConv)
184 : {
185 : case formula::FormulaGrammar::CONV_XL_R1C1:
186 8 : ExpandToTextR1C1(p, nLen, rStartPos, rEndPos);
187 8 : break;
188 : case formula::FormulaGrammar::CONV_OOO:
189 : case formula::FormulaGrammar::CONV_XL_A1:
190 : default:
191 8 : ExpandToTextA1(p, nLen, rStartPos, rEndPos);
192 : }
193 16 : }
194 :
195 : }
196 :
197 4 : ScRefFinder::ScRefFinder(
198 : const String& rFormula, const ScAddress& rPos,
199 : ScDocument* pDocument, formula::FormulaGrammar::AddressConvention eConvP) :
200 : aFormula( rFormula ),
201 : eConv( eConvP ),
202 : pDoc( pDocument ),
203 4 : maPos(rPos)
204 : {
205 4 : nSelStart = nSelEnd = nFound = 0;
206 4 : }
207 :
208 4 : ScRefFinder::~ScRefFinder()
209 : {
210 4 : }
211 :
212 16 : static sal_uInt16 lcl_NextFlags( sal_uInt16 nOld )
213 : {
214 16 : sal_uInt16 nNew = nOld & 7; // die drei Abs-Flags
215 16 : nNew = ( nNew - 1 ) & 7; // weiterzaehlen
216 :
217 16 : if (!(nOld & SCA_TAB_3D))
218 16 : nNew &= ~SCA_TAB_ABSOLUTE; // not 3D -> never absolute!
219 :
220 16 : return ( nOld & 0xfff8 ) | nNew;
221 : }
222 :
223 16 : void ScRefFinder::ToggleRel( xub_StrLen nStartPos, xub_StrLen nEndPos )
224 : {
225 16 : xub_StrLen nLen = aFormula.Len();
226 16 : if (!nLen)
227 16 : return;
228 16 : const sal_Unicode* pSource = aFormula.GetBuffer(); // for quick access
229 :
230 : // expand selection, and instead of selection start- and end-index
231 :
232 16 : if ( nEndPos < nStartPos )
233 0 : ::std::swap(nEndPos, nStartPos);
234 :
235 16 : ExpandToText(pSource, nLen, nStartPos, nEndPos, eConv);
236 :
237 16 : String aResult;
238 16 : String aExpr;
239 16 : String aSep;
240 16 : ScAddress aAddr;
241 16 : nFound = 0;
242 :
243 16 : xub_StrLen nLoopStart = nStartPos;
244 48 : while ( nLoopStart <= nEndPos )
245 : {
246 : // Determine the stard and end positions of a text segment.
247 16 : xub_StrLen nEStart = FindStartPos(pSource, nLoopStart, nEndPos);
248 16 : xub_StrLen nEEnd = FindEndPos(pSource, nEStart, nEndPos, eConv);
249 :
250 16 : aSep = aFormula.Copy( nLoopStart, nEStart-nLoopStart );
251 16 : aExpr = aFormula.Copy( nEStart, nEEnd-nEStart );
252 :
253 : // Check the validity of the expression, and toggle the relative flag.
254 16 : ScAddress::Details aDetails(eConv, maPos.Row(), maPos.Col());
255 16 : sal_uInt16 nResult = aAddr.Parse(aExpr, pDoc, aDetails);
256 16 : if ( nResult & SCA_VALID )
257 : {
258 16 : sal_uInt16 nFlags = lcl_NextFlags( nResult );
259 16 : aAddr.Format(aExpr, nFlags, pDoc, aDetails);
260 :
261 16 : xub_StrLen nAbsStart = nStartPos+aResult.Len()+aSep.Len();
262 :
263 16 : if (!nFound) // first reference ?
264 16 : nSelStart = nAbsStart;
265 16 : nSelEnd = nAbsStart+aExpr.Len(); // selection, no indizes
266 16 : ++nFound;
267 : }
268 :
269 : // assemble
270 :
271 16 : aResult += aSep;
272 16 : aResult += aExpr;
273 :
274 16 : nLoopStart = nEEnd;
275 : }
276 :
277 16 : String aTotal = aFormula.Copy( 0, nStartPos );
278 16 : aTotal += aResult;
279 16 : aTotal += aFormula.Copy( nEndPos+1 );
280 :
281 16 : aFormula = aTotal;
282 : }
283 :
284 :
285 :
286 :
287 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|