File: | home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx |
Warning: | line 720, column 25 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
21 | #include <algorithm> | |||
22 | ||||
23 | #include <string.h> | |||
24 | #include <limits.h> | |||
25 | #include <osl/diagnose.h> | |||
26 | #include <sal/log.hxx> | |||
27 | ||||
28 | #include <com/sun/star/sheet/FormulaToken.hpp> | |||
29 | #include <formula/errorcodes.hxx> | |||
30 | #include <formula/token.hxx> | |||
31 | #include <formula/tokenarray.hxx> | |||
32 | #include <formula/FormulaCompiler.hxx> | |||
33 | #include <formula/compiler.hxx> | |||
34 | #include <svl/sharedstringpool.hxx> | |||
35 | #include <memory> | |||
36 | ||||
37 | namespace formula | |||
38 | { | |||
39 | using namespace com::sun::star; | |||
40 | ||||
41 | ||||
42 | // --- helpers -------------------------------------------------------------- | |||
43 | ||||
44 | static bool lcl_IsReference( OpCode eOp, StackVar eType ) | |||
45 | { | |||
46 | return | |||
47 | (eOp == ocPush && (eType == svSingleRef || eType == svDoubleRef)) | |||
48 | || (eOp == ocColRowNameAuto && eType == svDoubleRef) | |||
49 | || (eOp == ocColRowName && eType == svSingleRef) | |||
50 | || (eOp == ocMatRef && eType == svSingleRef) | |||
51 | ; | |||
52 | } | |||
53 | ||||
54 | // --- class FormulaToken -------------------------------------------------------- | |||
55 | ||||
56 | FormulaToken::FormulaToken( StackVar eTypeP, OpCode e ) : | |||
57 | eOp(e), eType( eTypeP ), mnRefCnt(0) | |||
58 | { | |||
59 | } | |||
60 | ||||
61 | FormulaToken::FormulaToken( const FormulaToken& r ) : | |||
62 | eOp(r.eOp), eType( r.eType ), mnRefCnt(0) | |||
63 | { | |||
64 | } | |||
65 | ||||
66 | FormulaToken::~FormulaToken() | |||
67 | { | |||
68 | } | |||
69 | ||||
70 | bool FormulaToken::IsFunction() const | |||
71 | { | |||
72 | return (eOp != ocPush && eOp != ocBad && eOp != ocColRowName && | |||
73 | eOp != ocColRowNameAuto && eOp != ocName && eOp != ocDBArea && | |||
74 | eOp != ocTableRef && | |||
75 | (GetByte() != 0 // x parameters | |||
76 | || (SC_OPCODE_START_NO_PAR75 <= eOp && eOp < SC_OPCODE_STOP_NO_PAR84) // no parameter | |||
77 | || FormulaCompiler::IsOpCodeJumpCommand( eOp ) // @ jump commands | |||
78 | || (SC_OPCODE_START_1_PAR90 <= eOp && eOp < SC_OPCODE_STOP_1_PAR180) // one parameter | |||
79 | || (SC_OPCODE_START_2_PAR201 <= eOp && eOp < SC_OPCODE_STOP_2_PAR500) // x parameters (cByte==0 in | |||
80 | // FuncAutoPilot) | |||
81 | || eOp == ocMacro || eOp == ocExternal // macros, AddIns | |||
82 | || eOp == ocAnd || eOp == ocOr // former binary, now x parameters | |||
83 | || (eOp >= ocInternalBegin && eOp <= ocInternalEnd) // internal | |||
84 | )); | |||
85 | } | |||
86 | ||||
87 | ||||
88 | sal_uInt8 FormulaToken::GetParamCount() const | |||
89 | { | |||
90 | if ( eOp < SC_OPCODE_STOP_DIV35 && eOp != ocExternal && eOp != ocMacro && | |||
91 | !FormulaCompiler::IsOpCodeJumpCommand( eOp ) && | |||
92 | eOp != ocPercentSign ) | |||
93 | return 0; // parameters and specials | |||
94 | // ocIf... jump commands not for FAP, have cByte then | |||
95 | //2do: bool parameter whether FAP or not? | |||
96 | else if ( GetByte() ) | |||
97 | return GetByte(); // all functions, also ocExternal and ocMacro | |||
98 | else if (SC_OPCODE_START_BIN_OP50 <= eOp && eOp < SC_OPCODE_STOP_BIN_OP67) | |||
99 | return 2; // binary | |||
100 | else if ((SC_OPCODE_START_UN_OP70 <= eOp && eOp < SC_OPCODE_STOP_UN_OP71) | |||
101 | || eOp == ocPercentSign) | |||
102 | return 1; // unary | |||
103 | else if (SC_OPCODE_START_NO_PAR75 <= eOp && eOp < SC_OPCODE_STOP_NO_PAR84) | |||
104 | return 0; // no parameter | |||
105 | else if (SC_OPCODE_START_1_PAR90 <= eOp && eOp < SC_OPCODE_STOP_1_PAR180) | |||
106 | return 1; // one parameter | |||
107 | else if (FormulaCompiler::IsOpCodeJumpCommand( eOp )) | |||
108 | return 1; // only the condition counts as parameter | |||
109 | else | |||
110 | return 0; // all the rest, no Parameter, or | |||
111 | // if so then it should be in cByte | |||
112 | } | |||
113 | ||||
114 | bool FormulaToken::IsExternalRef() const | |||
115 | { | |||
116 | bool bRet = false; | |||
117 | switch (eType) | |||
118 | { | |||
119 | case svExternalSingleRef: | |||
120 | case svExternalDoubleRef: | |||
121 | case svExternalName: | |||
122 | bRet = true; | |||
123 | break; | |||
124 | default: | |||
125 | bRet = false; | |||
126 | break; | |||
127 | } | |||
128 | return bRet; | |||
129 | } | |||
130 | ||||
131 | bool FormulaToken::IsRef() const | |||
132 | { | |||
133 | switch (eType) | |||
134 | { | |||
135 | case svSingleRef: | |||
136 | case svDoubleRef: | |||
137 | case svExternalSingleRef: | |||
138 | case svExternalDoubleRef: | |||
139 | return true; | |||
140 | default: | |||
141 | if (eOp == ocTableRef) | |||
142 | return true; | |||
143 | } | |||
144 | ||||
145 | return false; | |||
146 | } | |||
147 | ||||
148 | bool FormulaToken::IsInForceArray() const | |||
149 | { | |||
150 | ParamClass eParam = GetInForceArray(); | |||
151 | return eParam == ParamClass::ForceArray || eParam == ParamClass::ReferenceOrForceArray | |||
152 | || eParam == ParamClass::ReferenceOrRefArray || eParam == ParamClass::ForceArrayReturn; | |||
153 | } | |||
154 | ||||
155 | bool FormulaToken::operator==( const FormulaToken& rToken ) const | |||
156 | { | |||
157 | // don't compare reference count! | |||
158 | return eType == rToken.eType && GetOpCode() == rToken.GetOpCode(); | |||
159 | } | |||
160 | ||||
161 | ||||
162 | // --- virtual dummy methods ------------------------------------------------- | |||
163 | ||||
164 | sal_uInt8 FormulaToken::GetByte() const | |||
165 | { | |||
166 | // ok to be called for any derived class | |||
167 | return 0; | |||
168 | } | |||
169 | ||||
170 | void FormulaToken::SetByte( sal_uInt8 ) | |||
171 | { | |||
172 | assert( !"virtual dummy called" )(static_cast <bool> (!"virtual dummy called") ? void (0 ) : __assert_fail ("!\"virtual dummy called\"", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 172, __extension__ __PRETTY_FUNCTION__)); | |||
173 | } | |||
174 | ||||
175 | ParamClass FormulaToken::GetInForceArray() const | |||
176 | { | |||
177 | // ok to be called for any derived class | |||
178 | return ParamClass::Unknown; | |||
179 | } | |||
180 | ||||
181 | void FormulaToken::SetInForceArray( ParamClass ) | |||
182 | { | |||
183 | assert( !"virtual dummy called" )(static_cast <bool> (!"virtual dummy called") ? void (0 ) : __assert_fail ("!\"virtual dummy called\"", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 183, __extension__ __PRETTY_FUNCTION__)); | |||
184 | } | |||
185 | ||||
186 | double FormulaToken::GetDouble() const | |||
187 | { | |||
188 | // This Get is worth an assert. | |||
189 | assert( !"virtual dummy called" )(static_cast <bool> (!"virtual dummy called") ? void (0 ) : __assert_fail ("!\"virtual dummy called\"", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 189, __extension__ __PRETTY_FUNCTION__)); | |||
190 | return 0.0; | |||
191 | } | |||
192 | ||||
193 | double & FormulaToken::GetDoubleAsReference() | |||
194 | { | |||
195 | // This Get is worth an assert. | |||
196 | assert( !"virtual dummy called" )(static_cast <bool> (!"virtual dummy called") ? void (0 ) : __assert_fail ("!\"virtual dummy called\"", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 196, __extension__ __PRETTY_FUNCTION__)); | |||
197 | static double fVal = 0.0; | |||
198 | return fVal; | |||
199 | } | |||
200 | ||||
201 | sal_Int16 FormulaToken::GetDoubleType() const | |||
202 | { | |||
203 | SAL_WARN( "formula.core", "FormulaToken::GetDoubleType: virtual dummy called" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaToken::GetDoubleType: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "203" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetDoubleType: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetDoubleType: virtual dummy called" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "203" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaToken::GetDoubleType: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "203" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetDoubleType: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetDoubleType: virtual dummy called" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "203" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
204 | return 0; | |||
205 | } | |||
206 | ||||
207 | void FormulaToken::SetDoubleType( sal_Int16 ) | |||
208 | { | |||
209 | assert( !"virtual dummy called" )(static_cast <bool> (!"virtual dummy called") ? void (0 ) : __assert_fail ("!\"virtual dummy called\"", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 209, __extension__ __PRETTY_FUNCTION__)); | |||
210 | } | |||
211 | ||||
212 | svl::SharedString FormulaToken::GetString() const | |||
213 | { | |||
214 | SAL_WARN( "formula.core", "FormulaToken::GetString: virtual dummy called" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaToken::GetString: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "214" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetString: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetString: virtual dummy called"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "214" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaToken::GetString: virtual dummy called") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "214" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetString: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetString: virtual dummy called"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "214" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
215 | return svl::SharedString(); // invalid string | |||
216 | } | |||
217 | ||||
218 | void FormulaToken::SetString( const svl::SharedString& ) | |||
219 | { | |||
220 | assert( !"virtual dummy called" )(static_cast <bool> (!"virtual dummy called") ? void (0 ) : __assert_fail ("!\"virtual dummy called\"", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 220, __extension__ __PRETTY_FUNCTION__)); | |||
221 | } | |||
222 | ||||
223 | sal_uInt16 FormulaToken::GetIndex() const | |||
224 | { | |||
225 | SAL_WARN( "formula.core", "FormulaToken::GetIndex: virtual dummy called" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaToken::GetIndex: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "225" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetIndex: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetIndex: virtual dummy called"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "225" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaToken::GetIndex: virtual dummy called") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "225" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetIndex: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetIndex: virtual dummy called"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "225" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
226 | return 0; | |||
227 | } | |||
228 | ||||
229 | void FormulaToken::SetIndex( sal_uInt16 ) | |||
230 | { | |||
231 | assert( !"virtual dummy called" )(static_cast <bool> (!"virtual dummy called") ? void (0 ) : __assert_fail ("!\"virtual dummy called\"", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 231, __extension__ __PRETTY_FUNCTION__)); | |||
232 | } | |||
233 | ||||
234 | sal_Int16 FormulaToken::GetSheet() const | |||
235 | { | |||
236 | SAL_WARN( "formula.core", "FormulaToken::GetSheet: virtual dummy called" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaToken::GetSheet: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "236" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetSheet: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetSheet: virtual dummy called"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "236" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaToken::GetSheet: virtual dummy called") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "236" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetSheet: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetSheet: virtual dummy called"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "236" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
237 | return -1; | |||
238 | } | |||
239 | ||||
240 | void FormulaToken::SetSheet( sal_Int16 ) | |||
241 | { | |||
242 | assert( !"virtual dummy called" )(static_cast <bool> (!"virtual dummy called") ? void (0 ) : __assert_fail ("!\"virtual dummy called\"", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 242, __extension__ __PRETTY_FUNCTION__)); | |||
243 | } | |||
244 | ||||
245 | short* FormulaToken::GetJump() const | |||
246 | { | |||
247 | SAL_WARN( "formula.core", "FormulaToken::GetJump: virtual dummy called" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaToken::GetJump: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "247" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetJump: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetJump: virtual dummy called"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "247" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaToken::GetJump: virtual dummy called") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "247" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetJump: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetJump: virtual dummy called"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "247" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
248 | return nullptr; | |||
249 | } | |||
250 | ||||
251 | ||||
252 | const OUString& FormulaToken::GetExternal() const | |||
253 | { | |||
254 | SAL_WARN( "formula.core", "FormulaToken::GetExternal: virtual dummy called" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaToken::GetExternal: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "254" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetExternal: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetExternal: virtual dummy called"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "254" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaToken::GetExternal: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "254" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetExternal: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetExternal: virtual dummy called"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "254" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
255 | static OUString aDummyString; | |||
256 | return aDummyString; | |||
257 | } | |||
258 | ||||
259 | FormulaToken* FormulaToken::GetFAPOrigToken() const | |||
260 | { | |||
261 | SAL_WARN( "formula.core", "FormulaToken::GetFAPOrigToken: virtual dummy called" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaToken::GetFAPOrigToken: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "261" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetFAPOrigToken: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetFAPOrigToken: virtual dummy called" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "261" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaToken::GetFAPOrigToken: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "261" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetFAPOrigToken: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetFAPOrigToken: virtual dummy called" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "261" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
262 | return nullptr; | |||
263 | } | |||
264 | ||||
265 | FormulaError FormulaToken::GetError() const | |||
266 | { | |||
267 | SAL_WARN( "formula.core", "FormulaToken::GetError: virtual dummy called" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaToken::GetError: virtual dummy called" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "267" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetError: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetError: virtual dummy called"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "267" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaToken::GetError: virtual dummy called") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "267" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaToken::GetError: virtual dummy called" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaToken::GetError: virtual dummy called"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "267" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
268 | return FormulaError::NONE; | |||
269 | } | |||
270 | ||||
271 | void FormulaToken::SetError( FormulaError ) | |||
272 | { | |||
273 | assert( !"virtual dummy called" )(static_cast <bool> (!"virtual dummy called") ? void (0 ) : __assert_fail ("!\"virtual dummy called\"", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 273, __extension__ __PRETTY_FUNCTION__)); | |||
274 | } | |||
275 | ||||
276 | const ScSingleRefData* FormulaToken::GetSingleRef() const | |||
277 | { | |||
278 | OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "278" ": "), "%s", "FormulaToken::GetSingleRef: virtual dummy called" ); } } while (false); | |||
279 | return nullptr; | |||
280 | } | |||
281 | ||||
282 | ScSingleRefData* FormulaToken::GetSingleRef() | |||
283 | { | |||
284 | OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "284" ": "), "%s", "FormulaToken::GetSingleRef: virtual dummy called" ); } } while (false); | |||
285 | return nullptr; | |||
286 | } | |||
287 | ||||
288 | const ScComplexRefData* FormulaToken::GetDoubleRef() const | |||
289 | { | |||
290 | OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "290" ": "), "%s", "FormulaToken::GetDoubleRef: virtual dummy called" ); } } while (false); | |||
291 | return nullptr; | |||
292 | } | |||
293 | ||||
294 | ScComplexRefData* FormulaToken::GetDoubleRef() | |||
295 | { | |||
296 | OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "296" ": "), "%s", "FormulaToken::GetDoubleRef: virtual dummy called" ); } } while (false); | |||
297 | return nullptr; | |||
298 | } | |||
299 | ||||
300 | const ScSingleRefData* FormulaToken::GetSingleRef2() const | |||
301 | { | |||
302 | OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "302" ": "), "%s", "FormulaToken::GetSingleRef2: virtual dummy called" ); } } while (false); | |||
303 | return nullptr; | |||
304 | } | |||
305 | ||||
306 | ScSingleRefData* FormulaToken::GetSingleRef2() | |||
307 | { | |||
308 | OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "308" ": "), "%s", "FormulaToken::GetSingleRef2: virtual dummy called" ); } } while (false); | |||
309 | return nullptr; | |||
310 | } | |||
311 | ||||
312 | const ScMatrix* FormulaToken::GetMatrix() const | |||
313 | { | |||
314 | OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "314" ": "), "%s", "FormulaToken::GetMatrix: virtual dummy called" ); } } while (false); | |||
315 | return nullptr; | |||
316 | } | |||
317 | ||||
318 | ScMatrix* FormulaToken::GetMatrix() | |||
319 | { | |||
320 | OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "320" ": "), "%s", "FormulaToken::GetMatrix: virtual dummy called" ); } } while (false); | |||
321 | return nullptr; | |||
322 | } | |||
323 | ||||
324 | ScJumpMatrix* FormulaToken::GetJumpMatrix() const | |||
325 | { | |||
326 | OSL_FAIL( "FormulaToken::GetJumpMatrix: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "326" ": "), "%s", "FormulaToken::GetJumpMatrix: virtual dummy called" ); } } while (false); | |||
327 | return nullptr; | |||
328 | } | |||
329 | const std::vector<ScComplexRefData>* FormulaToken::GetRefList() const | |||
330 | { | |||
331 | OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "331" ": "), "%s", "FormulaToken::GetRefList: virtual dummy called" ); } } while (false); | |||
332 | return nullptr; | |||
333 | } | |||
334 | ||||
335 | std::vector<ScComplexRefData>* FormulaToken::GetRefList() | |||
336 | { | |||
337 | OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "337" ": "), "%s", "FormulaToken::GetRefList: virtual dummy called" ); } } while (false); | |||
338 | return nullptr; | |||
339 | } | |||
340 | ||||
341 | bool FormulaToken::TextEqual( const FormulaToken& rToken ) const | |||
342 | { | |||
343 | return *this == rToken; | |||
344 | } | |||
345 | ||||
346 | // real implementations of virtual functions | |||
347 | ||||
348 | ||||
349 | sal_uInt8 FormulaByteToken::GetByte() const { return nByte; } | |||
350 | void FormulaByteToken::SetByte( sal_uInt8 n ) { nByte = n; } | |||
351 | ParamClass FormulaByteToken::GetInForceArray() const { return eInForceArray; } | |||
352 | void FormulaByteToken::SetInForceArray( ParamClass c ) { eInForceArray = c; } | |||
353 | bool FormulaByteToken::operator==( const FormulaToken& r ) const | |||
354 | { | |||
355 | return FormulaToken::operator==( r ) && nByte == r.GetByte() && | |||
356 | eInForceArray == r.GetInForceArray(); | |||
357 | } | |||
358 | ||||
359 | ||||
360 | FormulaToken* FormulaFAPToken::GetFAPOrigToken() const { return pOrigToken.get(); } | |||
361 | bool FormulaFAPToken::operator==( const FormulaToken& r ) const | |||
362 | { | |||
363 | return FormulaByteToken::operator==( r ) && pOrigToken == r.GetFAPOrigToken(); | |||
364 | } | |||
365 | ||||
366 | ||||
367 | short* FormulaJumpToken::GetJump() const { return pJump.get(); } | |||
368 | ParamClass FormulaJumpToken::GetInForceArray() const { return eInForceArray; } | |||
369 | void FormulaJumpToken::SetInForceArray( ParamClass c ) { eInForceArray = c; } | |||
370 | bool FormulaJumpToken::operator==( const FormulaToken& r ) const | |||
371 | { | |||
372 | return FormulaToken::operator==( r ) && pJump[0] == r.GetJump()[0] && | |||
373 | memcmp( pJump.get()+1, r.GetJump()+1, pJump[0] * sizeof(short) ) == 0 && | |||
374 | eInForceArray == r.GetInForceArray(); | |||
375 | } | |||
376 | FormulaJumpToken::~FormulaJumpToken() | |||
377 | { | |||
378 | } | |||
379 | ||||
380 | ||||
381 | bool FormulaTokenArray::AddFormulaToken( | |||
382 | const sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool, ExternalReferenceHelper* /*pExtRef*/) | |||
383 | { | |||
384 | bool bError = false; | |||
385 | const OpCode eOpCode = static_cast<OpCode>(rToken.OpCode); //! assuming equal values for the moment | |||
386 | ||||
387 | const uno::TypeClass eClass = rToken.Data.getValueTypeClass(); | |||
388 | switch ( eClass ) | |||
389 | { | |||
390 | case uno::TypeClass_VOID: | |||
391 | // empty data -> use AddOpCode (does some special cases) | |||
392 | AddOpCode( eOpCode ); | |||
393 | break; | |||
394 | case uno::TypeClass_DOUBLE: | |||
395 | // double is only used for "push" | |||
396 | if ( eOpCode == ocPush ) | |||
397 | AddDouble( rToken.Data.get<double>() ); | |||
398 | else | |||
399 | bError = true; | |||
400 | break; | |||
401 | case uno::TypeClass_LONG: | |||
402 | { | |||
403 | // long is svIndex, used for name / database area, or "byte" for spaces | |||
404 | sal_Int32 nValue = rToken.Data.get<sal_Int32>(); | |||
405 | if ( eOpCode == ocDBArea ) | |||
406 | Add( new formula::FormulaIndexToken( eOpCode, static_cast<sal_uInt16>(nValue) ) ); | |||
407 | else if ( eOpCode == ocTableRef ) | |||
408 | bError = true; /* TODO: implementation */ | |||
409 | else if ( eOpCode == ocSpaces ) | |||
410 | Add( new formula::FormulaByteToken( ocSpaces, static_cast<sal_uInt8>(nValue) ) ); | |||
411 | else | |||
412 | bError = true; | |||
413 | } | |||
414 | break; | |||
415 | case uno::TypeClass_STRING: | |||
416 | { | |||
417 | OUString aStrVal( rToken.Data.get<OUString>() ); | |||
418 | if ( eOpCode == ocPush ) | |||
419 | AddString(rSPool.intern(aStrVal)); | |||
420 | else if ( eOpCode == ocBad ) | |||
421 | AddBad( aStrVal ); | |||
422 | else if ( eOpCode == ocStringXML ) | |||
423 | AddStringXML( aStrVal ); | |||
424 | else if ( eOpCode == ocExternal || eOpCode == ocMacro ) | |||
425 | Add( new formula::FormulaExternalToken( eOpCode, aStrVal ) ); | |||
426 | else | |||
427 | bError = true; // unexpected string: don't know what to do with it | |||
428 | } | |||
429 | break; | |||
430 | default: | |||
431 | bError = true; | |||
432 | } // switch ( eClass ) | |||
433 | return bError; | |||
434 | } | |||
435 | ||||
436 | bool FormulaTokenArray::Fill( | |||
437 | const uno::Sequence<sheet::FormulaToken>& rSequence, | |||
438 | svl::SharedStringPool& rSPool, ExternalReferenceHelper* pExtRef ) | |||
439 | { | |||
440 | bool bError = false; | |||
441 | const sal_Int32 nCount = rSequence.getLength(); | |||
442 | for (sal_Int32 nPos=0; nPos<nCount; nPos++) | |||
443 | { | |||
444 | bool bOneError = AddFormulaToken(rSequence[nPos], rSPool, pExtRef); | |||
445 | if (bOneError) | |||
446 | { | |||
447 | AddOpCode( ocErrName); // add something that indicates an error | |||
448 | bError = true; | |||
449 | } | |||
450 | } | |||
451 | return bError; | |||
452 | } | |||
453 | ||||
454 | void FormulaTokenArray::DelRPN() | |||
455 | { | |||
456 | if( nRPN ) | |||
457 | { | |||
458 | FormulaToken** p = pRPN; | |||
459 | for( sal_uInt16 i = 0; i < nRPN; i++ ) | |||
460 | { | |||
461 | (*p++)->DecRef(); | |||
462 | } | |||
463 | delete [] pRPN; | |||
464 | } | |||
465 | pRPN = nullptr; | |||
466 | nRPN = 0; | |||
467 | } | |||
468 | ||||
469 | FormulaToken* FormulaTokenArray::FirstToken() const | |||
470 | { | |||
471 | if (!pCode || nLen == 0) | |||
472 | return nullptr; | |||
473 | return pCode[0]; | |||
474 | } | |||
475 | ||||
476 | FormulaToken* FormulaTokenArray::PeekPrev( sal_uInt16 & nIdx ) const | |||
477 | { | |||
478 | if (0 < nIdx && nIdx <= nLen) | |||
479 | return pCode[--nIdx]; | |||
480 | return nullptr; | |||
481 | } | |||
482 | ||||
483 | FormulaToken* FormulaTokenArray::FirstRPNToken() const | |||
484 | { | |||
485 | if (!pRPN || nRPN == 0) | |||
486 | return nullptr; | |||
487 | return pRPN[0]; | |||
488 | } | |||
489 | ||||
490 | bool FormulaTokenArray::HasReferences() const | |||
491 | { | |||
492 | for (auto i: Tokens()) | |||
493 | { | |||
494 | if (i->IsRef()) | |||
495 | return true; | |||
496 | } | |||
497 | ||||
498 | for (auto i: RPNTokens()) | |||
499 | { | |||
500 | if (i->IsRef()) | |||
501 | return true; | |||
502 | } | |||
503 | ||||
504 | return false; | |||
505 | } | |||
506 | ||||
507 | bool FormulaTokenArray::HasExternalRef() const | |||
508 | { | |||
509 | for (auto i: Tokens()) | |||
510 | { | |||
511 | if (i->IsExternalRef()) | |||
512 | return true; | |||
513 | } | |||
514 | return false; | |||
515 | } | |||
516 | ||||
517 | bool FormulaTokenArray::HasOpCode( OpCode eOp ) const | |||
518 | { | |||
519 | for (auto i: Tokens()) | |||
520 | { | |||
521 | if (i->GetOpCode() == eOp) | |||
522 | return true; | |||
523 | } | |||
524 | return false; | |||
525 | } | |||
526 | ||||
527 | bool FormulaTokenArray::HasOpCodeRPN( OpCode eOp ) const | |||
528 | { | |||
529 | for (auto i: RPNTokens()) | |||
530 | { | |||
531 | if (i->GetOpCode() == eOp) | |||
532 | return true; | |||
533 | } | |||
534 | return false; | |||
535 | } | |||
536 | ||||
537 | bool FormulaTokenArray::HasNameOrColRowName() const | |||
538 | { | |||
539 | for (auto i: Tokens()) | |||
540 | { | |||
541 | if (i->GetType() == svIndex || i->GetOpCode() == ocColRowName ) | |||
542 | return true; | |||
543 | } | |||
544 | return false; | |||
545 | } | |||
546 | ||||
547 | bool FormulaTokenArray::HasOpCodes(const unordered_opcode_set& rOpCodes) const | |||
548 | { | |||
549 | for (auto i: Tokens()) | |||
550 | { | |||
551 | if (rOpCodes.count(i->GetOpCode()) > 0) | |||
552 | return true; | |||
553 | } | |||
554 | ||||
555 | return false; | |||
556 | } | |||
557 | ||||
558 | FormulaTokenArray::FormulaTokenArray() : | |||
559 | pRPN(nullptr), | |||
560 | nLen(0), | |||
561 | nRPN(0), | |||
562 | nError(FormulaError::NONE), | |||
563 | nMode(ScRecalcMode::NORMAL), | |||
564 | bHyperLink(false), | |||
565 | mbFromRangeName(false), | |||
566 | mbShareable(true), | |||
567 | mbFinalized(false) | |||
568 | { | |||
569 | } | |||
570 | ||||
571 | FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray& rArr ) | |||
572 | { | |||
573 | Assign( rArr ); | |||
574 | } | |||
575 | ||||
576 | FormulaTokenArray::~FormulaTokenArray() | |||
577 | { | |||
578 | FormulaTokenArray::Clear(); | |||
579 | } | |||
580 | ||||
581 | void FormulaTokenArray::Finalize() | |||
582 | { | |||
583 | if( nLen && !mbFinalized ) | |||
584 | { | |||
585 | // Add() overallocates, so reallocate to the minimum needed size. | |||
586 | std::unique_ptr<FormulaToken*[]> newCode(new FormulaToken*[ nLen ]); | |||
587 | std::copy(&pCode[0], &pCode[nLen], newCode.get()); | |||
588 | pCode = std::move( newCode ); | |||
589 | mbFinalized = true; | |||
590 | } | |||
591 | } | |||
592 | ||||
593 | void FormulaTokenArray::Assign( const FormulaTokenArray& r ) | |||
594 | { | |||
595 | nLen = r.nLen; | |||
596 | nRPN = r.nRPN; | |||
597 | nError = r.nError; | |||
598 | nMode = r.nMode; | |||
599 | bHyperLink = r.bHyperLink; | |||
600 | mbFromRangeName = r.mbFromRangeName; | |||
601 | mbShareable = r.mbShareable; | |||
602 | mbFinalized = r.mbFinalized; | |||
603 | pCode = nullptr; | |||
604 | pRPN = nullptr; | |||
605 | FormulaToken** pp; | |||
606 | if( nLen ) | |||
607 | { | |||
608 | pCode.reset(new FormulaToken*[ nLen ]); | |||
609 | pp = pCode.get(); | |||
610 | memcpy( pp, r.pCode.get(), nLen * sizeof( FormulaToken* ) ); | |||
611 | for( sal_uInt16 i = 0; i < nLen; i++ ) | |||
612 | (*pp++)->IncRef(); | |||
613 | mbFinalized = true; | |||
614 | } | |||
615 | if( nRPN ) | |||
616 | { | |||
617 | pp = pRPN = new FormulaToken*[ nRPN ]; | |||
618 | memcpy( pp, r.pRPN, nRPN * sizeof( FormulaToken* ) ); | |||
619 | for( sal_uInt16 i = 0; i < nRPN; i++ ) | |||
620 | (*pp++)->IncRef(); | |||
621 | } | |||
622 | } | |||
623 | ||||
624 | /// Optimisation for efficiently creating StringXML placeholders | |||
625 | void FormulaTokenArray::Assign( sal_uInt16 nCode, FormulaToken **pTokens ) | |||
626 | { | |||
627 | assert( nLen == 0 )(static_cast <bool> (nLen == 0) ? void (0) : __assert_fail ("nLen == 0", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 627, __extension__ __PRETTY_FUNCTION__)); | |||
628 | assert( pCode == nullptr )(static_cast <bool> (pCode == nullptr) ? void (0) : __assert_fail ("pCode == nullptr", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 628, __extension__ __PRETTY_FUNCTION__)); | |||
629 | ||||
630 | nLen = nCode; | |||
631 | pCode.reset(new FormulaToken*[ nLen ]); | |||
632 | mbFinalized = true; | |||
633 | ||||
634 | for( sal_uInt16 i = 0; i < nLen; i++ ) | |||
635 | { | |||
636 | FormulaToken *t = pTokens[ i ]; | |||
637 | assert( t->GetOpCode() == ocStringXML )(static_cast <bool> (t->GetOpCode() == ocStringXML) ? void (0) : __assert_fail ("t->GetOpCode() == ocStringXML" , "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 637, __extension__ __PRETTY_FUNCTION__)); | |||
638 | pCode[ i ] = t; | |||
639 | t->IncRef(); | |||
640 | } | |||
641 | } | |||
642 | ||||
643 | FormulaTokenArray& FormulaTokenArray::operator=( const FormulaTokenArray& rArr ) | |||
644 | { | |||
645 | if(this == &rArr) | |||
646 | return *this; | |||
647 | ||||
648 | Clear(); | |||
649 | Assign( rArr ); | |||
650 | return *this; | |||
651 | } | |||
652 | ||||
653 | void FormulaTokenArray::Clear() | |||
654 | { | |||
655 | if( nRPN ) DelRPN(); | |||
656 | if( pCode ) | |||
657 | { | |||
658 | FormulaToken** p = pCode.get(); | |||
659 | for( sal_uInt16 i = 0; i < nLen; i++ ) | |||
660 | { | |||
661 | (*p++)->DecRef(); | |||
662 | } | |||
663 | pCode.reset(); | |||
664 | } | |||
665 | pRPN = nullptr; | |||
666 | nError = FormulaError::NONE; | |||
667 | nLen = nRPN = 0; | |||
668 | bHyperLink = false; | |||
669 | mbFromRangeName = false; | |||
670 | mbShareable = true; | |||
671 | mbFinalized = false; | |||
672 | ClearRecalcMode(); | |||
673 | } | |||
674 | ||||
675 | void FormulaTokenArray::CheckToken( const FormulaToken& /*r*/ ) | |||
676 | { | |||
677 | // Do nothing. | |||
678 | } | |||
679 | ||||
680 | void FormulaTokenArray::CheckAllRPNTokens() | |||
681 | { | |||
682 | if( nRPN ) | |||
683 | { | |||
684 | FormulaToken** p = pRPN; | |||
685 | for( sal_uInt16 i = 0; i < nRPN; i++ ) | |||
686 | { | |||
687 | CheckToken( *p[ i ] ); | |||
688 | } | |||
689 | } | |||
690 | } | |||
691 | ||||
692 | FormulaToken* FormulaTokenArray::AddToken( const FormulaToken& r ) | |||
693 | { | |||
694 | return Add( r.Clone() ); | |||
695 | } | |||
696 | ||||
697 | FormulaToken* FormulaTokenArray::MergeArray( ) | |||
698 | { | |||
699 | return nullptr; | |||
700 | } | |||
701 | ||||
702 | FormulaToken* FormulaTokenArray::ReplaceToken( sal_uInt16 nOffset, FormulaToken* t, | |||
703 | FormulaTokenArray::ReplaceMode eMode ) | |||
704 | { | |||
705 | if (nOffset < nLen) | |||
| ||||
706 | { | |||
707 | CheckToken(*t); | |||
708 | t->IncRef(); | |||
709 | FormulaToken* p = pCode[nOffset]; | |||
710 | pCode[nOffset] = t; | |||
711 | if (eMode == CODE_AND_RPN && p->GetRef() > 1) | |||
712 | { | |||
713 | for (sal_uInt16 i=0; i < nRPN; ++i) | |||
714 | { | |||
715 | if (pRPN[i] == p) | |||
716 | { | |||
717 | t->IncRef(); | |||
718 | pRPN[i] = t; | |||
719 | p->DecRef(); | |||
720 | if (p->GetRef() == 1) | |||
| ||||
721 | break; // for | |||
722 | } | |||
723 | } | |||
724 | } | |||
725 | p->DecRef(); // may be dead now | |||
726 | return t; | |||
727 | } | |||
728 | else | |||
729 | { | |||
730 | t->DeleteIfZeroRef(); | |||
731 | return nullptr; | |||
732 | } | |||
733 | } | |||
734 | ||||
735 | sal_uInt16 FormulaTokenArray::RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount ) | |||
736 | { | |||
737 | if (nOffset < nLen) | |||
738 | { | |||
739 | SAL_WARN_IF( nOffset + nCount > nLen, "formula.core",do { if (true && (nOffset + nCount > nLen)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "formula.core" )) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "740" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "740" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "740" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "740" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
740 | "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen)do { if (true && (nOffset + nCount > nLen)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "formula.core" )) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "740" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "740" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "740" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "740" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
741 | const sal_uInt16 nStop = ::std::min( static_cast<sal_uInt16>(nOffset + nCount), nLen); | |||
742 | nCount = nStop - nOffset; | |||
743 | for (sal_uInt16 j = nOffset; j < nStop; ++j) | |||
744 | { | |||
745 | FormulaToken* p = pCode[j]; | |||
746 | if (p->GetRef() > 1) | |||
747 | { | |||
748 | for (sal_uInt16 i=0; i < nRPN; ++i) | |||
749 | { | |||
750 | if (pRPN[i] == p) | |||
751 | { | |||
752 | // Shift remaining tokens in pRPN down. | |||
753 | for (sal_uInt16 x=i+1; x < nRPN; ++x) | |||
754 | { | |||
755 | pRPN[x-1] = pRPN[x]; | |||
756 | } | |||
757 | --nRPN; | |||
758 | ||||
759 | p->DecRef(); | |||
760 | if (p->GetRef() == 1) | |||
761 | break; // for | |||
762 | } | |||
763 | } | |||
764 | } | |||
765 | p->DecRef(); // may be dead now | |||
766 | } | |||
767 | ||||
768 | // Shift remaining tokens in pCode down. | |||
769 | for (sal_uInt16 x = nStop; x < nLen; ++x) | |||
770 | { | |||
771 | pCode[x-nCount] = pCode[x]; | |||
772 | } | |||
773 | nLen -= nCount; | |||
774 | ||||
775 | return nCount; | |||
776 | } | |||
777 | else | |||
778 | { | |||
779 | SAL_WARN("formula.core","FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen) == 1 ) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "779" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "779" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen) == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "779" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core"), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "779" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
780 | return 0; | |||
781 | } | |||
782 | } | |||
783 | ||||
784 | FormulaToken* FormulaTokenArray::Add( FormulaToken* t ) | |||
785 | { | |||
786 | assert(!mbFinalized)(static_cast <bool> (!mbFinalized) ? void (0) : __assert_fail ("!mbFinalized", "/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" , 786, __extension__ __PRETTY_FUNCTION__)); | |||
787 | if (mbFinalized) | |||
788 | { | |||
789 | t->DeleteIfZeroRef(); | |||
790 | return nullptr; | |||
791 | } | |||
792 | ||||
793 | // Allocating an array of size FORMULA_MAXTOKENS is simple, but that results in relatively large | |||
794 | // allocations that malloc() implementations usually do not handle as efficiently as smaller | |||
795 | // sizes (not only in terms of memory usage but also speed). Since most token arrays are going | |||
796 | // to be small, start with a small array and resize only if needed. Eventually Finalize() will | |||
797 | // reallocate the memory to size exactly matching the requirements. | |||
798 | const size_t MAX_FAST_TOKENS = 32; | |||
799 | if( !pCode ) | |||
800 | pCode.reset(new FormulaToken*[ MAX_FAST_TOKENS ]); | |||
801 | if( nLen == MAX_FAST_TOKENS ) | |||
802 | { | |||
803 | FormulaToken** tmp = new FormulaToken*[ FORMULA_MAXTOKENS8192 ]; | |||
804 | std::copy(&pCode[0], &pCode[MAX_FAST_TOKENS], tmp); | |||
805 | pCode.reset(tmp); | |||
806 | } | |||
807 | if( nLen < FORMULA_MAXTOKENS8192 - 1 ) | |||
808 | { | |||
809 | CheckToken(*t); | |||
810 | pCode[ nLen++ ] = t; | |||
811 | t->IncRef(); | |||
812 | if( t->GetOpCode() == ocArrayClose ) | |||
813 | return MergeArray(); | |||
814 | return t; | |||
815 | } | |||
816 | else | |||
817 | { | |||
818 | t->DeleteIfZeroRef(); | |||
819 | if ( nLen == FORMULA_MAXTOKENS8192 - 1 ) | |||
820 | { | |||
821 | t = new FormulaByteToken( ocStop ); | |||
822 | pCode[ nLen++ ] = t; | |||
823 | t->IncRef(); | |||
824 | } | |||
825 | return nullptr; | |||
826 | } | |||
827 | } | |||
828 | ||||
829 | FormulaToken* FormulaTokenArray::AddString( const svl::SharedString& rStr ) | |||
830 | { | |||
831 | return Add( new FormulaStringToken( rStr ) ); | |||
832 | } | |||
833 | ||||
834 | FormulaToken* FormulaTokenArray::AddDouble( double fVal ) | |||
835 | { | |||
836 | return Add( new FormulaDoubleToken( fVal ) ); | |||
837 | } | |||
838 | ||||
839 | void FormulaTokenArray::AddExternal( const sal_Unicode* pStr ) | |||
840 | { | |||
841 | AddExternal( OUString( pStr ) ); | |||
842 | } | |||
843 | ||||
844 | FormulaToken* FormulaTokenArray::AddExternal( const OUString& rStr, | |||
845 | OpCode eOp /* = ocExternal */ ) | |||
846 | { | |||
847 | return Add( new FormulaExternalToken( eOp, rStr ) ); | |||
848 | } | |||
849 | ||||
850 | FormulaToken* FormulaTokenArray::AddBad( const OUString& rStr ) | |||
851 | { | |||
852 | return Add( new FormulaStringOpToken( ocBad, svl::SharedString( rStr ) ) ); // string not interned | |||
853 | } | |||
854 | ||||
855 | FormulaToken* FormulaTokenArray::AddStringXML( const OUString& rStr ) | |||
856 | { | |||
857 | return Add( new FormulaStringOpToken( ocStringXML, svl::SharedString( rStr ) ) ); // string not interned | |||
858 | } | |||
859 | ||||
860 | ||||
861 | void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits ) | |||
862 | { | |||
863 | const unsigned nExclusive = static_cast<sal_uInt8>(nBits & ScRecalcMode::EMask); | |||
864 | if (nExclusive) | |||
865 | { | |||
866 | unsigned nExBit; | |||
867 | if (nExclusive & (nExclusive - 1)) | |||
868 | { | |||
869 | // More than one bit set, use highest priority. | |||
870 | for (nExBit = 1; (nExBit & static_cast<sal_uInt8>(ScRecalcMode::EMask)) != 0; nExBit <<= 1) | |||
871 | { | |||
872 | if (nExclusive & nExBit) | |||
873 | break; | |||
874 | } | |||
875 | } | |||
876 | else | |||
877 | { | |||
878 | // Only one bit is set. | |||
879 | nExBit = nExclusive; | |||
880 | } | |||
881 | // Set exclusive bit if priority is higher than existing. | |||
882 | if (nExBit < static_cast<sal_uInt8>(nMode & ScRecalcMode::EMask)) | |||
883 | SetMaskedRecalcMode( static_cast<ScRecalcMode>(nExBit)); | |||
884 | } | |||
885 | SetCombinedBitsRecalcMode( nBits ); | |||
886 | } | |||
887 | ||||
888 | ||||
889 | bool FormulaTokenArray::HasMatrixDoubleRefOps() const | |||
890 | { | |||
891 | if ( pRPN && nRPN ) | |||
892 | { | |||
893 | // RPN-Interpreter simulation. | |||
894 | // Simply assumes a double as return value of each function. | |||
895 | std::unique_ptr<FormulaToken*[]> pStack(new FormulaToken* [nRPN]); | |||
896 | FormulaToken* pResult = new FormulaDoubleToken( 0.0 ); | |||
897 | short sp = 0; | |||
898 | for ( auto t: RPNTokens() ) | |||
899 | { | |||
900 | OpCode eOp = t->GetOpCode(); | |||
901 | sal_uInt8 nParams = t->GetParamCount(); | |||
902 | switch ( eOp ) | |||
903 | { | |||
904 | case ocAdd : | |||
905 | case ocSub : | |||
906 | case ocMul : | |||
907 | case ocDiv : | |||
908 | case ocPow : | |||
909 | case ocPower : | |||
910 | case ocAmpersand : | |||
911 | case ocEqual : | |||
912 | case ocNotEqual : | |||
913 | case ocLess : | |||
914 | case ocGreater : | |||
915 | case ocLessEqual : | |||
916 | case ocGreaterEqual : | |||
917 | { | |||
918 | for ( sal_uInt8 k = nParams; k; k-- ) | |||
919 | { | |||
920 | if ( sp >= k && pStack[sp-k]->GetType() == svDoubleRef ) | |||
921 | { | |||
922 | pResult->Delete(); | |||
923 | return true; | |||
924 | } | |||
925 | } | |||
926 | } | |||
927 | break; | |||
928 | default: | |||
929 | { | |||
930 | // added to avoid warnings | |||
931 | } | |||
932 | } | |||
933 | if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() ) ) | |||
934 | pStack[sp++] = t; | |||
935 | else if (FormulaCompiler::IsOpCodeJumpCommand( eOp )) | |||
936 | { // ignore Jumps, pop previous Result (Condition) | |||
937 | if ( sp ) | |||
938 | --sp; | |||
939 | } | |||
940 | else | |||
941 | { // pop parameters, push result | |||
942 | sp = sal::static_int_cast<short>( sp - nParams ); | |||
943 | if ( sp < 0 ) | |||
944 | { | |||
945 | SAL_WARN("formula.core", "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "945" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "945" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "945" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "945" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
946 | sp = 0; | |||
947 | } | |||
948 | pStack[sp++] = pResult; | |||
949 | } | |||
950 | } | |||
951 | pResult->Delete(); | |||
952 | } | |||
953 | ||||
954 | return false; | |||
955 | } | |||
956 | ||||
957 | // --- Formula rewrite of a token array | |||
958 | ||||
959 | inline bool MissingConventionODF::isRewriteNeeded( OpCode eOp ) const | |||
960 | { | |||
961 | switch (eOp) | |||
962 | { | |||
963 | case ocGammaDist: | |||
964 | case ocPoissonDist: | |||
965 | case ocAddress: | |||
966 | case ocLogInv: | |||
967 | case ocLogNormDist: | |||
968 | case ocNormDist: | |||
969 | return true; | |||
970 | case ocMissing: | |||
971 | case ocLog: | |||
972 | return isPODF(); // rewrite only for PODF | |||
973 | case ocDBCount: | |||
974 | case ocDBCount2: | |||
975 | return isODFF(); // rewrite only for ODFF | |||
976 | default: | |||
977 | return false; | |||
978 | } | |||
979 | } | |||
980 | ||||
981 | /* | |||
982 | fdo 81596 | |||
983 | To be implemented yet: | |||
984 | ocExternal: ? | |||
985 | ocMacro: ? | |||
986 | ocIndex: INDEX() ? | |||
987 | */ | |||
988 | inline bool MissingConventionOOXML::isRewriteNeeded( OpCode eOp ) | |||
989 | { | |||
990 | switch (eOp) | |||
991 | { | |||
992 | case ocIf: | |||
993 | ||||
994 | case ocExternal: | |||
995 | case ocEuroConvert: | |||
996 | case ocMacro: | |||
997 | ||||
998 | case ocRound: | |||
999 | case ocRoundUp: | |||
1000 | case ocRoundDown: | |||
1001 | ||||
1002 | case ocIndex: | |||
1003 | ||||
1004 | case ocCeil: | |||
1005 | case ocFloor: | |||
1006 | ||||
1007 | case ocGammaDist: | |||
1008 | case ocFDist_LT: | |||
1009 | case ocPoissonDist: | |||
1010 | case ocNormDist: | |||
1011 | case ocLogInv: | |||
1012 | case ocLogNormDist: | |||
1013 | case ocHypGeomDist: | |||
1014 | ||||
1015 | case ocDBCount: | |||
1016 | case ocDBCount2: | |||
1017 | return true; | |||
1018 | ||||
1019 | default: | |||
1020 | return false; | |||
1021 | } | |||
1022 | } | |||
1023 | ||||
1024 | namespace { | |||
1025 | ||||
1026 | class FormulaMissingContext | |||
1027 | { | |||
1028 | public: | |||
1029 | const FormulaToken* mpFunc; | |||
1030 | int mnCurArg; | |||
1031 | ||||
1032 | void Clear() { mpFunc = nullptr; mnCurArg = 0; } | |||
1033 | inline bool AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const; | |||
1034 | bool AddMissingExternal( FormulaTokenArray* pNewArr ) const; | |||
1035 | bool AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const; | |||
1036 | void AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const; | |||
1037 | }; | |||
1038 | ||||
1039 | } | |||
1040 | ||||
1041 | void FormulaMissingContext::AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const | |||
1042 | { | |||
1043 | if ( !mpFunc ) | |||
1044 | return; | |||
1045 | ||||
1046 | switch (rConv.getConvention()) | |||
1047 | { | |||
1048 | case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF: | |||
1049 | case MissingConvention::FORMULA_MISSING_CONVENTION_PODF: | |||
1050 | { | |||
1051 | switch (mpFunc->GetOpCode()) | |||
1052 | { | |||
1053 | case ocGammaDist: | |||
1054 | if (mnCurArg == 2) | |||
1055 | { | |||
1056 | pNewArr->AddOpCode( ocSep ); | |||
1057 | pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true() | |||
1058 | } | |||
1059 | break; | |||
1060 | case ocPoissonDist: | |||
1061 | if (mnCurArg == 1) | |||
1062 | { | |||
1063 | pNewArr->AddOpCode( ocSep ); | |||
1064 | pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true() | |||
1065 | } | |||
1066 | break; | |||
1067 | case ocNormDist: | |||
1068 | if ( mnCurArg == 2 ) | |||
1069 | { | |||
1070 | pNewArr->AddOpCode( ocSep ); | |||
1071 | pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true() | |||
1072 | } | |||
1073 | break; | |||
1074 | case ocLogInv: | |||
1075 | case ocLogNormDist: | |||
1076 | if ( mnCurArg == 0 ) | |||
1077 | { | |||
1078 | pNewArr->AddOpCode( ocSep ); | |||
1079 | pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0 | |||
1080 | } | |||
1081 | if ( mnCurArg <= 1 ) | |||
1082 | { | |||
1083 | pNewArr->AddOpCode( ocSep ); | |||
1084 | pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0 | |||
1085 | } | |||
1086 | break; | |||
1087 | case ocLog: | |||
1088 | if ( rConv.isPODF() && mnCurArg == 0 ) | |||
1089 | { | |||
1090 | pNewArr->AddOpCode( ocSep ); | |||
1091 | pNewArr->AddDouble( 10.0 ); // 2nd, basis 10 | |||
1092 | } | |||
1093 | break; | |||
1094 | default: | |||
1095 | break; | |||
1096 | } | |||
1097 | } | |||
1098 | break; | |||
1099 | case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML: | |||
1100 | { | |||
1101 | switch (mpFunc->GetOpCode()) | |||
1102 | { | |||
1103 | case ocIf: | |||
1104 | if( mnCurArg == 0 ) | |||
1105 | { | |||
1106 | // Excel needs at least two parameters in IF function | |||
1107 | pNewArr->AddOpCode( ocSep ); | |||
1108 | pNewArr->AddOpCode( ocTrue ); // 2nd, true() as function | |||
1109 | pNewArr->AddOpCode( ocOpen ); // so the result is of logical type | |||
1110 | pNewArr->AddOpCode( ocClose ); // and survives roundtrip | |||
1111 | } | |||
1112 | break; | |||
1113 | ||||
1114 | case ocEuroConvert: | |||
1115 | if ( mnCurArg == 2 ) | |||
1116 | { | |||
1117 | pNewArr->AddOpCode( ocSep ); | |||
1118 | pNewArr->AddDouble( 0.0 ); // 4th, FullPrecision = false() | |||
1119 | } | |||
1120 | break; | |||
1121 | ||||
1122 | case ocPoissonDist: | |||
1123 | if (mnCurArg == 1) | |||
1124 | { | |||
1125 | pNewArr->AddOpCode( ocSep ); | |||
1126 | pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true() | |||
1127 | } | |||
1128 | break; | |||
1129 | ||||
1130 | case ocGammaDist: | |||
1131 | case ocFDist_LT: | |||
1132 | case ocNormDist: | |||
1133 | if (mnCurArg == 2) | |||
1134 | { | |||
1135 | pNewArr->AddOpCode( ocSep ); | |||
1136 | pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true() | |||
1137 | } | |||
1138 | break; | |||
1139 | ||||
1140 | case ocLogInv: | |||
1141 | case ocLogNormDist: | |||
1142 | if ( mnCurArg == 0 ) | |||
1143 | { | |||
1144 | pNewArr->AddOpCode( ocSep ); | |||
1145 | pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0 | |||
1146 | } | |||
1147 | if ( mnCurArg <= 1 ) | |||
1148 | { | |||
1149 | pNewArr->AddOpCode( ocSep ); | |||
1150 | pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0 | |||
1151 | } | |||
1152 | break; | |||
1153 | ||||
1154 | case ocHypGeomDist: | |||
1155 | if ( mnCurArg == 3 ) | |||
1156 | { | |||
1157 | pNewArr->AddOpCode( ocSep ); | |||
1158 | pNewArr->AddDouble( 0.0 ); // 5th, Cumulative = false() | |||
1159 | } | |||
1160 | break; | |||
1161 | ||||
1162 | case ocRound: | |||
1163 | case ocRoundUp: | |||
1164 | case ocRoundDown: | |||
1165 | if( mnCurArg == 0 ) | |||
1166 | { | |||
1167 | // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel | |||
1168 | pNewArr->AddOpCode( ocSep ); | |||
1169 | pNewArr->AddDouble( 0.0 ); // 2nd, 0.0 | |||
1170 | } | |||
1171 | break; | |||
1172 | ||||
1173 | default: | |||
1174 | break; | |||
1175 | } | |||
1176 | } | |||
1177 | break; | |||
1178 | } | |||
1179 | ||||
1180 | } | |||
1181 | ||||
1182 | inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const | |||
1183 | { | |||
1184 | if (mnCurArg == nArg) | |||
1185 | { | |||
1186 | pNewArr->AddDouble( f ); | |||
1187 | return true; | |||
1188 | } | |||
1189 | return false; | |||
1190 | } | |||
1191 | ||||
1192 | bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray *pNewArr ) const | |||
1193 | { | |||
1194 | // Only called for PODF, not ODFF. No need to distinguish. | |||
1195 | ||||
1196 | const OUString &rName = mpFunc->GetExternal(); | |||
1197 | ||||
1198 | // initial (fast) check: | |||
1199 | sal_Unicode nLastChar = rName[ rName.getLength() - 1]; | |||
1200 | if ( nLastChar != 't' && nLastChar != 'm' ) | |||
1201 | return false; | |||
1202 | ||||
1203 | if (rName.equalsIgnoreAsciiCase( | |||
1204 | "com.sun.star.sheet.addin.Analysis.getAccrint" )) | |||
1205 | { | |||
1206 | return AddDefaultArg( pNewArr, 4, 1000.0 ); | |||
1207 | } | |||
1208 | if (rName.equalsIgnoreAsciiCase( | |||
1209 | "com.sun.star.sheet.addin.Analysis.getAccrintm" )) | |||
1210 | { | |||
1211 | return AddDefaultArg( pNewArr, 3, 1000.0 ); | |||
1212 | } | |||
1213 | return false; | |||
1214 | } | |||
1215 | ||||
1216 | bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const | |||
1217 | { | |||
1218 | if ( !mpFunc ) | |||
1219 | return false; | |||
1220 | ||||
1221 | bool bRet = false; | |||
1222 | const OpCode eOp = mpFunc->GetOpCode(); | |||
1223 | ||||
1224 | switch (rConv.getConvention()) | |||
1225 | { | |||
1226 | case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF: | |||
1227 | { | |||
1228 | // Add for ODFF | |||
1229 | switch (eOp) | |||
1230 | { | |||
1231 | case ocAddress: | |||
1232 | return AddDefaultArg( pNewArr, 2, 1.0 ); // abs | |||
1233 | default: | |||
1234 | break; | |||
1235 | } | |||
1236 | } | |||
1237 | break; | |||
1238 | case MissingConvention::FORMULA_MISSING_CONVENTION_PODF: | |||
1239 | { | |||
1240 | // Add for PODF | |||
1241 | switch (eOp) | |||
1242 | { | |||
1243 | case ocAddress: | |||
1244 | return AddDefaultArg( pNewArr, 2, 1.0 ); // abs | |||
1245 | case ocFixed: | |||
1246 | return AddDefaultArg( pNewArr, 1, 2.0 ); | |||
1247 | case ocBetaDist: | |||
1248 | case ocBetaInv: | |||
1249 | case ocPMT: | |||
1250 | return AddDefaultArg( pNewArr, 3, 0.0 ); | |||
1251 | case ocIpmt: | |||
1252 | case ocPpmt: | |||
1253 | return AddDefaultArg( pNewArr, 4, 0.0 ); | |||
1254 | case ocPV: | |||
1255 | case ocFV: | |||
1256 | bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt | |||
1257 | bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v | |||
1258 | break; | |||
1259 | case ocRate: | |||
1260 | bRet |= AddDefaultArg( pNewArr, 1, 0.0 ); // pmt | |||
1261 | bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // fv | |||
1262 | bRet |= AddDefaultArg( pNewArr, 4, 0.0 ); // type | |||
1263 | break; | |||
1264 | case ocExternal: | |||
1265 | return AddMissingExternal( pNewArr ); | |||
1266 | ||||
1267 | // --- more complex cases --- | |||
1268 | ||||
1269 | case ocOffset: | |||
1270 | // FIXME: rather tough | |||
1271 | // if arg 3 (height) omitted, export arg1 (rows) | |||
1272 | break; | |||
1273 | default: | |||
1274 | break; | |||
1275 | } | |||
1276 | } | |||
1277 | break; | |||
1278 | case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML: | |||
1279 | { | |||
1280 | switch (eOp) | |||
1281 | { | |||
1282 | case ocExternal: | |||
1283 | return AddMissingExternal( pNewArr ); | |||
1284 | default: | |||
1285 | break; | |||
1286 | } | |||
1287 | } | |||
1288 | break; | |||
1289 | } | |||
1290 | ||||
1291 | return bRet; | |||
1292 | } | |||
1293 | ||||
1294 | bool FormulaTokenArray::NeedsPodfRewrite( const MissingConventionODF & rConv ) | |||
1295 | { | |||
1296 | for ( auto i: Tokens() ) | |||
1297 | { | |||
1298 | if ( rConv.isRewriteNeeded( i->GetOpCode())) | |||
1299 | return true; | |||
1300 | } | |||
1301 | return false; | |||
1302 | } | |||
1303 | ||||
1304 | bool FormulaTokenArray::NeedsOoxmlRewrite() | |||
1305 | { | |||
1306 | for ( auto i: Tokens() ) | |||
1307 | { | |||
1308 | if ( MissingConventionOOXML::isRewriteNeeded( i->GetOpCode())) | |||
1309 | return true; | |||
1310 | } | |||
1311 | return false; | |||
1312 | } | |||
1313 | ||||
1314 | ||||
1315 | FormulaTokenArray * FormulaTokenArray::RewriteMissing( const MissingConvention & rConv ) | |||
1316 | { | |||
1317 | const size_t nAlloc = 256; | |||
1318 | FormulaMissingContext aCtx[ nAlloc ]; | |||
1319 | ||||
1320 | /* TODO: with some effort we might be able to merge the two almost | |||
1321 | * identical function stacks into one and generalize things, otherwise | |||
1322 | * adding yet another "omit argument" would be copypasta. */ | |||
1323 | ||||
1324 | int aOpCodeAddressStack[ nAlloc ]; // use of ADDRESS() function | |||
1325 | const int nOmitAddressArg = 3; // ADDRESS() 4th parameter A1/R1C1 | |||
1326 | ||||
1327 | int aOpCodeDcountStack[ nAlloc ]; // use of DCOUNT()/DCOUNTA() function | |||
1328 | const int nOmitDcountArg = 1; // DCOUNT() and DCOUNTA() 2nd parameter DatabaseField if 0 | |||
1329 | ||||
1330 | sal_uInt16 nTokens = GetLen() + 1; | |||
1331 | FormulaMissingContext* pCtx = (nAlloc < nTokens ? new FormulaMissingContext[nTokens] : &aCtx[0]); | |||
1332 | int* pOcas = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeAddressStack[0]); | |||
1333 | int* pOcds = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeDcountStack[0]); | |||
1334 | // Never go below 0, never use 0, mpFunc always NULL. | |||
1335 | pCtx[0].Clear(); | |||
1336 | int nFn = 0; | |||
1337 | int nOcas = 0; | |||
1338 | int nOcds = 0; | |||
1339 | ||||
1340 | FormulaTokenArray *pNewArr = new FormulaTokenArray; | |||
1341 | // At least ScRecalcMode::ALWAYS needs to be set. | |||
1342 | pNewArr->AddRecalcMode( GetRecalcMode()); | |||
1343 | ||||
1344 | FormulaTokenArrayPlainIterator aIter(*this); | |||
1345 | for ( FormulaToken *pCur = aIter.First(); pCur; pCur = aIter.Next() ) | |||
1346 | { | |||
1347 | bool bAdd = true; | |||
1348 | // Don't write the expression of the new inserted ADDRESS() parameter. | |||
1349 | // Do NOT omit the new second parameter of INDIRECT() though. If that | |||
1350 | // was done for both, INDIRECT() actually could calculate different and | |||
1351 | // valid (but wrong) results with the then changed return value of | |||
1352 | // ADDRESS(). Better let it generate an error instead. | |||
1353 | for (int i = nOcas; i-- > 0 && bAdd; ) | |||
1354 | { | |||
1355 | if (pCtx[ pOcas[ i ] ].mnCurArg == nOmitAddressArg) | |||
1356 | { | |||
1357 | // Omit everything except a trailing separator, the leading | |||
1358 | // separator is omitted below. The other way around would leave | |||
1359 | // an extraneous separator if no parameter followed. | |||
1360 | if (pOcas[ i ] != nFn || pCur->GetOpCode() != ocSep) | |||
1361 | bAdd = false; | |||
1362 | } | |||
1363 | } | |||
1364 | // Strip the 2nd argument (leaving empty) of DCOUNT() and DCOUNTA() if | |||
1365 | // it is 0. | |||
1366 | for (int i = nOcds; i-- > 0 && bAdd; ) | |||
1367 | { | |||
1368 | if (pCtx[ pOcds[ i ] ].mnCurArg == nOmitDcountArg) | |||
1369 | { | |||
1370 | // Omit only a literal 0 value, nothing else. | |||
1371 | if (pOcds[ i ] == nFn && pCur->GetOpCode() == ocPush && pCur->GetType() == svDouble && | |||
1372 | pCur->GetDouble() == 0.0) | |||
1373 | { | |||
1374 | // No other expression, between separators. | |||
1375 | FormulaToken* p = aIter.PeekPrevNoSpaces(); | |||
1376 | if (p && p->GetOpCode() == ocSep) | |||
1377 | { | |||
1378 | p = aIter.PeekNextNoSpaces(); | |||
1379 | if (p && p->GetOpCode() == ocSep) | |||
1380 | bAdd = false; | |||
1381 | } | |||
1382 | } | |||
1383 | } | |||
1384 | } | |||
1385 | switch ( pCur->GetOpCode() ) | |||
1386 | { | |||
1387 | case ocOpen: | |||
1388 | { | |||
1389 | ++nFn; // all following operations on _that_ function | |||
1390 | pCtx[ nFn ].mpFunc = aIter.PeekPrevNoSpaces(); | |||
1391 | pCtx[ nFn ].mnCurArg = 0; | |||
1392 | OpCode eOp; | |||
1393 | if (rConv.isPODF() && pCtx[ nFn ].mpFunc && pCtx[ nFn ].mpFunc->GetOpCode() == ocAddress) | |||
1394 | pOcas[ nOcas++ ] = nFn; // entering ADDRESS() if PODF | |||
1395 | else if ((rConv.isODFF() || rConv.isOOXML()) && pCtx[ nFn ].mpFunc) | |||
1396 | { | |||
1397 | eOp = pCtx[ nFn ].mpFunc->GetOpCode(); | |||
1398 | if (eOp == ocDBCount || eOp == ocDBCount2) | |||
1399 | pOcds[ nOcds++ ] = nFn; // entering DCOUNT() or DCOUNTA() if ODFF or OOXML | |||
1400 | } | |||
1401 | } | |||
1402 | break; | |||
1403 | case ocClose: | |||
1404 | pCtx[ nFn ].AddMoreArgs( pNewArr, rConv ); | |||
1405 | SAL_WARN_IF(nFn <= 0, "formula.core", "FormulaTokenArray::RewriteMissing: underflow")do { if (true && (nFn <= 0)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "formula.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "FormulaTokenArray::RewriteMissing: underflow" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "1405" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "FormulaTokenArray::RewriteMissing: underflow" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::RewriteMissing: underflow"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "1405" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "FormulaTokenArray::RewriteMissing: underflow") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "1405" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "FormulaTokenArray::RewriteMissing: underflow" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "FormulaTokenArray::RewriteMissing: underflow"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("formula.core" ), ("/home/maarten/src/libreoffice/core/formula/source/core/api/token.cxx" ":" "1405" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1406 | if (nOcas > 0 && pOcas[ nOcas-1 ] == nFn) | |||
1407 | --nOcas; // leaving ADDRESS() | |||
1408 | else if (nOcds > 0 && pOcds[ nOcds-1 ] == nFn) | |||
1409 | --nOcds; // leaving DCOUNT() or DCOUNTA() | |||
1410 | if (nFn > 0) | |||
1411 | --nFn; | |||
1412 | break; | |||
1413 | case ocSep: | |||
1414 | pCtx[ nFn ].mnCurArg++; | |||
1415 | // Omit leading separator of ADDRESS() parameter. | |||
1416 | if (nOcas && pOcas[ nOcas-1 ] == nFn && pCtx[ nFn ].mnCurArg == nOmitAddressArg) | |||
1417 | { | |||
1418 | bAdd = false; | |||
1419 | } | |||
1420 | break; | |||
1421 | case ocMissing: | |||
1422 | if ( bAdd ) | |||
1423 | bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv ); | |||
1424 | break; | |||
1425 | default: | |||
1426 | break; | |||
1427 | } | |||
1428 | if (bAdd) | |||
1429 | { | |||
1430 | OpCode eOp = pCur->GetOpCode(); | |||
1431 | if ( ( eOp == ocCeil || eOp == ocFloor || | |||
1432 | ( eOp == ocLogNormDist && pCur->GetByte() == 4 ) ) && | |||
1433 | rConv.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML ) | |||
1434 | { | |||
1435 | switch ( eOp ) | |||
1436 | { | |||
1437 | case ocCeil : | |||
1438 | eOp = ocCeil_Math; | |||
1439 | break; | |||
1440 | case ocFloor : | |||
1441 | eOp = ocFloor_Math; | |||
1442 | break; | |||
1443 | case ocLogNormDist : | |||
1444 | eOp = ocLogNormDist_MS; | |||
1445 | break; | |||
1446 | default : | |||
1447 | eOp = ocNone; | |||
1448 | break; | |||
1449 | } | |||
1450 | FormulaToken *pToken = new FormulaToken( svByte, eOp ); | |||
1451 | pNewArr->Add( pToken ); | |||
1452 | } | |||
1453 | else if ( eOp == ocHypGeomDist && | |||
1454 | rConv.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML ) | |||
1455 | { | |||
1456 | FormulaToken *pToken = new FormulaToken( svByte, ocHypGeomDist_MS ); | |||
1457 | pNewArr->Add( pToken ); | |||
1458 | } | |||
1459 | else | |||
1460 | pNewArr->AddToken( *pCur ); | |||
1461 | } | |||
1462 | } | |||
1463 | ||||
1464 | if (pOcds != &aOpCodeDcountStack[0]) | |||
1465 | delete [] pOcds; | |||
1466 | if (pOcas != &aOpCodeAddressStack[0]) | |||
1467 | delete [] pOcas; | |||
1468 | if (pCtx != &aCtx[0]) | |||
1469 | delete [] pCtx; | |||
1470 | ||||
1471 | return pNewArr; | |||
1472 | } | |||
1473 | ||||
1474 | bool FormulaTokenArray::MayReferenceFollow() | |||
1475 | { | |||
1476 | if ( pCode && nLen > 0 ) | |||
1477 | { | |||
1478 | // ignore trailing spaces | |||
1479 | sal_uInt16 i = nLen - 1; | |||
1480 | while ( i > 0 && pCode[i]->GetOpCode() == SC_OPCODE_SPACES16 ) | |||
1481 | { | |||
1482 | --i; | |||
1483 | } | |||
1484 | if ( i > 0 || pCode[i]->GetOpCode() != SC_OPCODE_SPACES16 ) | |||
1485 | { | |||
1486 | OpCode eOp = pCode[i]->GetOpCode(); | |||
1487 | if ( (SC_OPCODE_START_BIN_OP50 <= eOp && eOp < SC_OPCODE_STOP_BIN_OP67 ) || | |||
1488 | (SC_OPCODE_START_UN_OP70 <= eOp && eOp < SC_OPCODE_STOP_UN_OP71 ) || | |||
1489 | eOp == SC_OPCODE_OPEN10 || eOp == SC_OPCODE_SEP12 ) | |||
1490 | { | |||
1491 | return true; | |||
1492 | } | |||
1493 | } | |||
1494 | } | |||
1495 | return false; | |||
1496 | } | |||
1497 | FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp ) | |||
1498 | { | |||
1499 | FormulaToken* pRet = nullptr; | |||
1500 | switch ( eOp ) | |||
1501 | { | |||
1502 | case ocOpen: | |||
1503 | case ocClose: | |||
1504 | case ocSep: | |||
1505 | case ocArrayOpen: | |||
1506 | case ocArrayClose: | |||
1507 | case ocArrayRowSep: | |||
1508 | case ocArrayColSep: | |||
1509 | pRet = new FormulaToken( svSep,eOp ); | |||
1510 | break; | |||
1511 | case ocIf: | |||
1512 | case ocIfError: | |||
1513 | case ocIfNA: | |||
1514 | case ocChoose: | |||
1515 | { | |||
1516 | short nJump[FORMULA_MAXJUMPCOUNT32 + 1]; | |||
1517 | if ( eOp == ocIf ) | |||
1518 | nJump[ 0 ] = 3; | |||
1519 | else if ( eOp == ocChoose ) | |||
1520 | nJump[ 0 ] = FORMULA_MAXJUMPCOUNT32 + 1; | |||
1521 | else | |||
1522 | nJump[ 0 ] = 2; | |||
1523 | pRet = new FormulaJumpToken( eOp, nJump ); | |||
1524 | } | |||
1525 | break; | |||
1526 | default: | |||
1527 | pRet = new FormulaByteToken( eOp, 0, ParamClass::Unknown ); | |||
1528 | break; | |||
1529 | } | |||
1530 | return Add( pRet ); | |||
1531 | } | |||
1532 | ||||
1533 | void FormulaTokenArray::ReinternStrings( svl::SharedStringPool& rPool ) | |||
1534 | { | |||
1535 | for (auto i: Tokens()) | |||
1536 | { | |||
1537 | switch (i->GetType()) | |||
1538 | { | |||
1539 | case svString: | |||
1540 | i->SetString( rPool.intern( i->GetString().getString())); | |||
1541 | break; | |||
1542 | default: | |||
1543 | ; // nothing | |||
1544 | } | |||
1545 | } | |||
1546 | } | |||
1547 | ||||
1548 | ||||
1549 | /*----------------------------------------------------------------------*/ | |||
1550 | ||||
1551 | FormulaTokenIterator::Item::Item(const FormulaTokenArray* pArray, short pc, short stop) : | |||
1552 | pArr(pArray), nPC(pc), nStop(stop) | |||
1553 | { | |||
1554 | } | |||
1555 | ||||
1556 | FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray& rArr ) | |||
1557 | { | |||
1558 | Push( &rArr ); | |||
1559 | } | |||
1560 | ||||
1561 | FormulaTokenIterator::~FormulaTokenIterator() | |||
1562 | { | |||
1563 | } | |||
1564 | ||||
1565 | void FormulaTokenIterator::Push( const FormulaTokenArray* pArr ) | |||
1566 | { | |||
1567 | FormulaTokenIterator::Item item(pArr, -1, SHRT_MAX32767); | |||
1568 | ||||
1569 | maStack.push_back(item); | |||
1570 | } | |||
1571 | ||||
1572 | void FormulaTokenIterator::Pop() | |||
1573 | { | |||
1574 | maStack.pop_back(); | |||
1575 | } | |||
1576 | ||||
1577 | void FormulaTokenIterator::Reset() | |||
1578 | { | |||
1579 | while( maStack.size() > 1 ) | |||
1580 | maStack.pop_back(); | |||
1581 | ||||
1582 | maStack.back().nPC = -1; | |||
1583 | } | |||
1584 | ||||
1585 | FormulaToken* FormulaTokenArrayPlainIterator::GetNextName() | |||
1586 | { | |||
1587 | if( mpFTA->GetArray() ) | |||
1588 | { | |||
1589 | while ( mnIndex < mpFTA->GetLen() ) | |||
1590 | { | |||
1591 | FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ]; | |||
1592 | if( t->GetType() == svIndex ) | |||
1593 | return t; | |||
1594 | } | |||
1595 | } | |||
1596 | return nullptr; | |||
1597 | } | |||
1598 | ||||
1599 | const FormulaToken* FormulaTokenIterator::Next() | |||
1600 | { | |||
1601 | const FormulaToken* t = GetNonEndOfPathToken( ++maStack.back().nPC ); | |||
1602 | if( !t && maStack.size() > 1 ) | |||
1603 | { | |||
1604 | Pop(); | |||
1605 | t = Next(); | |||
1606 | } | |||
1607 | return t; | |||
1608 | } | |||
1609 | ||||
1610 | const FormulaToken* FormulaTokenIterator::PeekNextOperator() | |||
1611 | { | |||
1612 | const FormulaToken* t = nullptr; | |||
1613 | short nIdx = maStack.back().nPC; | |||
1614 | for (;;) | |||
1615 | { | |||
1616 | t = GetNonEndOfPathToken( ++nIdx); | |||
1617 | if (t == nullptr || t->GetOpCode() != ocPush) | |||
1618 | break; // ignore operands | |||
1619 | } | |||
1620 | if (!t && maStack.size() > 1) | |||
1621 | { | |||
1622 | FormulaTokenIterator::Item aHere = maStack.back(); | |||
1623 | maStack.pop_back(); | |||
1624 | t = PeekNextOperator(); | |||
1625 | maStack.push_back(aHere); | |||
1626 | } | |||
1627 | return t; | |||
1628 | } | |||
1629 | ||||
1630 | //! The nPC counts after a Push() are -1 | |||
1631 | ||||
1632 | void FormulaTokenIterator::Jump( short nStart, short nNext, short nStop ) | |||
1633 | { | |||
1634 | maStack.back().nPC = nNext; | |||
1635 | if( nStart != nNext ) | |||
1636 | { | |||
1637 | Push( maStack.back().pArr ); | |||
1638 | maStack.back().nPC = nStart; | |||
1639 | maStack.back().nStop = nStop; | |||
1640 | } | |||
1641 | } | |||
1642 | ||||
1643 | void FormulaTokenIterator::ReInit( const FormulaTokenArray& rArr ) | |||
1644 | { | |||
1645 | maStack.clear(); | |||
1646 | Push( &rArr ); | |||
1647 | } | |||
1648 | ||||
1649 | const FormulaToken* FormulaTokenIterator::GetNonEndOfPathToken( short nIdx ) const | |||
1650 | { | |||
1651 | FormulaTokenIterator::Item cur = maStack.back(); | |||
1652 | ||||
1653 | if (nIdx < cur.pArr->GetCodeLen() && nIdx < cur.nStop) | |||
1654 | { | |||
1655 | const FormulaToken* t = cur.pArr->GetCode()[ nIdx ]; | |||
1656 | // such an OpCode ends an IF() or CHOOSE() path | |||
1657 | return (t->GetOpCode() == ocSep || t->GetOpCode() == ocClose) ? nullptr : t; | |||
1658 | } | |||
1659 | return nullptr; | |||
1660 | } | |||
1661 | ||||
1662 | bool FormulaTokenIterator::IsEndOfPath() const | |||
1663 | { | |||
1664 | return GetNonEndOfPathToken( maStack.back().nPC + 1) == nullptr; | |||
1665 | } | |||
1666 | ||||
1667 | FormulaToken* FormulaTokenArrayPlainIterator::GetNextReference() | |||
1668 | { | |||
1669 | while( mnIndex < mpFTA->GetLen() ) | |||
1670 | { | |||
1671 | FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ]; | |||
1672 | switch( t->GetType() ) | |||
1673 | { | |||
1674 | case svSingleRef: | |||
1675 | case svDoubleRef: | |||
1676 | case svExternalSingleRef: | |||
1677 | case svExternalDoubleRef: | |||
1678 | return t; | |||
1679 | default: | |||
1680 | { | |||
1681 | // added to avoid warnings | |||
1682 | } | |||
1683 | } | |||
1684 | } | |||
1685 | return nullptr; | |||
1686 | } | |||
1687 | ||||
1688 | FormulaToken* FormulaTokenArrayPlainIterator::GetNextColRowName() | |||
1689 | { | |||
1690 | while( mnIndex < mpFTA->GetLen() ) | |||
1691 | { | |||
1692 | FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ]; | |||
1693 | if ( t->GetOpCode() == ocColRowName ) | |||
1694 | return t; | |||
1695 | } | |||
1696 | return nullptr; | |||
1697 | } | |||
1698 | ||||
1699 | FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceRPN() | |||
1700 | { | |||
1701 | while( mnIndex < mpFTA->GetCodeLen() ) | |||
1702 | { | |||
1703 | FormulaToken* t = mpFTA->GetCode()[ mnIndex++ ]; | |||
1704 | switch( t->GetType() ) | |||
1705 | { | |||
1706 | case svSingleRef: | |||
1707 | case svDoubleRef: | |||
1708 | case svExternalSingleRef: | |||
1709 | case svExternalDoubleRef: | |||
1710 | return t; | |||
1711 | default: | |||
1712 | { | |||
1713 | // added to avoid warnings | |||
1714 | } | |||
1715 | } | |||
1716 | } | |||
1717 | return nullptr; | |||
1718 | } | |||
1719 | ||||
1720 | FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceOrName() | |||
1721 | { | |||
1722 | if( mpFTA->GetArray() ) | |||
1723 | { | |||
1724 | while ( mnIndex < mpFTA->GetLen() ) | |||
1725 | { | |||
1726 | FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ]; | |||
1727 | switch( t->GetType() ) | |||
1728 | { | |||
1729 | case svSingleRef: | |||
1730 | case svDoubleRef: | |||
1731 | case svIndex: | |||
1732 | case svExternalSingleRef: | |||
1733 | case svExternalDoubleRef: | |||
1734 | case svExternalName: | |||
1735 | return t; | |||
1736 | default: | |||
1737 | { | |||
1738 | // added to avoid warnings | |||
1739 | } | |||
1740 | } | |||
1741 | } | |||
1742 | } | |||
1743 | return nullptr; | |||
1744 | } | |||
1745 | ||||
1746 | FormulaToken* FormulaTokenArrayPlainIterator::Next() | |||
1747 | { | |||
1748 | if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() ) | |||
1749 | return mpFTA->GetArray()[ mnIndex++ ]; | |||
1750 | else | |||
1751 | return nullptr; | |||
1752 | } | |||
1753 | ||||
1754 | FormulaToken* FormulaTokenArrayPlainIterator::NextNoSpaces() | |||
1755 | { | |||
1756 | if( mpFTA->GetArray() ) | |||
1757 | { | |||
1758 | while( (mnIndex < mpFTA->GetLen()) && (mpFTA->GetArray()[ mnIndex ]->GetOpCode() == ocSpaces) ) | |||
1759 | ++mnIndex; | |||
1760 | if( mnIndex < mpFTA->GetLen() ) | |||
1761 | return mpFTA->GetArray()[ mnIndex++ ]; | |||
1762 | } | |||
1763 | return nullptr; | |||
1764 | } | |||
1765 | ||||
1766 | FormulaToken* FormulaTokenArrayPlainIterator::NextRPN() | |||
1767 | { | |||
1768 | if( mpFTA->GetCode() && mnIndex < mpFTA->GetCodeLen() ) | |||
1769 | return mpFTA->GetCode()[ mnIndex++ ]; | |||
1770 | else | |||
1771 | return nullptr; | |||
1772 | } | |||
1773 | ||||
1774 | FormulaToken* FormulaTokenArrayPlainIterator::PrevRPN() | |||
1775 | { | |||
1776 | if( mpFTA->GetCode() && mnIndex ) | |||
1777 | return mpFTA->GetCode()[ --mnIndex ]; | |||
1778 | else | |||
1779 | return nullptr; | |||
1780 | } | |||
1781 | ||||
1782 | FormulaToken* FormulaTokenArrayPlainIterator::PeekNext() | |||
1783 | { | |||
1784 | if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() ) | |||
1785 | return mpFTA->GetArray()[ mnIndex ]; | |||
1786 | else | |||
1787 | return nullptr; | |||
1788 | } | |||
1789 | ||||
1790 | FormulaToken* FormulaTokenArrayPlainIterator::PeekNextNoSpaces() const | |||
1791 | { | |||
1792 | if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() ) | |||
1793 | { | |||
1794 | sal_uInt16 j = mnIndex; | |||
1795 | while ( j < mpFTA->GetLen() && mpFTA->GetArray()[j]->GetOpCode() == ocSpaces ) | |||
1796 | j++; | |||
1797 | if ( j < mpFTA->GetLen() ) | |||
1798 | return mpFTA->GetArray()[ j ]; | |||
1799 | else | |||
1800 | return nullptr; | |||
1801 | } | |||
1802 | else | |||
1803 | return nullptr; | |||
1804 | } | |||
1805 | ||||
1806 | FormulaToken* FormulaTokenArrayPlainIterator::PeekPrevNoSpaces() const | |||
1807 | { | |||
1808 | if( mpFTA->GetArray() && mnIndex > 1 ) | |||
1809 | { | |||
1810 | sal_uInt16 j = mnIndex - 2; | |||
1811 | while ( mpFTA->GetArray()[j]->GetOpCode() == ocSpaces && j > 0 ) | |||
1812 | j--; | |||
1813 | if ( j > 0 || mpFTA->GetArray()[j]->GetOpCode() != ocSpaces ) | |||
1814 | return mpFTA->GetArray()[ j ]; | |||
1815 | else | |||
1816 | return nullptr; | |||
1817 | } | |||
1818 | else | |||
1819 | return nullptr; | |||
1820 | } | |||
1821 | ||||
1822 | void FormulaTokenArrayPlainIterator::AfterRemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount ) | |||
1823 | { | |||
1824 | const sal_uInt16 nStop = std::min( static_cast<sal_uInt16>(nOffset + nCount), mpFTA->GetLen()); | |||
1825 | ||||
1826 | if (mnIndex >= nOffset) | |||
1827 | { | |||
1828 | if (mnIndex < nStop) | |||
1829 | mnIndex = nOffset + 1; | |||
1830 | else | |||
1831 | mnIndex -= nStop - nOffset; | |||
1832 | } | |||
1833 | } | |||
1834 | ||||
1835 | // real implementations of virtual functions | |||
1836 | ||||
1837 | ||||
1838 | double FormulaDoubleToken::GetDouble() const { return fDouble; } | |||
1839 | double & FormulaDoubleToken::GetDoubleAsReference() { return fDouble; } | |||
1840 | ||||
1841 | sal_Int16 FormulaDoubleToken::GetDoubleType() const | |||
1842 | { | |||
1843 | // This is a plain double value without type information, don't emit a | |||
1844 | // warning via FormulaToken::GetDoubleType(). | |||
1845 | return 0; | |||
1846 | } | |||
1847 | ||||
1848 | bool FormulaDoubleToken::operator==( const FormulaToken& r ) const | |||
1849 | { | |||
1850 | return FormulaToken::operator==( r ) && fDouble == r.GetDouble(); | |||
1851 | } | |||
1852 | ||||
1853 | sal_Int16 FormulaTypedDoubleToken::GetDoubleType() const | |||
1854 | { | |||
1855 | return mnType; | |||
1856 | } | |||
1857 | ||||
1858 | void FormulaTypedDoubleToken::SetDoubleType( sal_Int16 nType ) | |||
1859 | { | |||
1860 | mnType = nType; | |||
1861 | } | |||
1862 | ||||
1863 | bool FormulaTypedDoubleToken::operator==( const FormulaToken& r ) const | |||
1864 | { | |||
1865 | return FormulaDoubleToken::operator==( r ) && mnType == r.GetDoubleType(); | |||
1866 | } | |||
1867 | ||||
1868 | FormulaStringToken::FormulaStringToken( const svl::SharedString& r ) : | |||
1869 | FormulaToken( svString ), maString( r ) | |||
1870 | { | |||
1871 | } | |||
1872 | ||||
1873 | FormulaStringToken::FormulaStringToken( const FormulaStringToken& r ) : | |||
1874 | FormulaToken( r ), maString( r.maString ) {} | |||
1875 | ||||
1876 | FormulaToken* FormulaStringToken::Clone() const | |||
1877 | { | |||
1878 | return new FormulaStringToken(*this); | |||
1879 | } | |||
1880 | ||||
1881 | svl::SharedString FormulaStringToken::GetString() const | |||
1882 | { | |||
1883 | return maString; | |||
1884 | } | |||
1885 | ||||
1886 | void FormulaStringToken::SetString( const svl::SharedString& rStr ) | |||
1887 | { | |||
1888 | maString = rStr; | |||
1889 | } | |||
1890 | ||||
1891 | bool FormulaStringToken::operator==( const FormulaToken& r ) const | |||
1892 | { | |||
1893 | return FormulaToken::operator==( r ) && maString == r.GetString(); | |||
1894 | } | |||
1895 | ||||
1896 | FormulaStringOpToken::FormulaStringOpToken( OpCode e, const svl::SharedString& r ) : | |||
1897 | FormulaByteToken( e, 0, svString, ParamClass::Unknown ), maString( r ) {} | |||
1898 | ||||
1899 | FormulaStringOpToken::FormulaStringOpToken( const FormulaStringOpToken& r ) : | |||
1900 | FormulaByteToken( r ), maString( r.maString ) {} | |||
1901 | ||||
1902 | FormulaToken* FormulaStringOpToken::Clone() const | |||
1903 | { | |||
1904 | return new FormulaStringOpToken(*this); | |||
1905 | } | |||
1906 | ||||
1907 | svl::SharedString FormulaStringOpToken::GetString() const | |||
1908 | { | |||
1909 | return maString; | |||
1910 | } | |||
1911 | ||||
1912 | void FormulaStringOpToken::SetString( const svl::SharedString& rStr ) | |||
1913 | { | |||
1914 | maString = rStr; | |||
1915 | } | |||
1916 | ||||
1917 | bool FormulaStringOpToken::operator==( const FormulaToken& r ) const | |||
1918 | { | |||
1919 | return FormulaByteToken::operator==( r ) && maString == r.GetString(); | |||
1920 | } | |||
1921 | ||||
1922 | sal_uInt16 FormulaIndexToken::GetIndex() const { return nIndex; } | |||
1923 | void FormulaIndexToken::SetIndex( sal_uInt16 n ) { nIndex = n; } | |||
1924 | sal_Int16 FormulaIndexToken::GetSheet() const { return mnSheet; } | |||
1925 | void FormulaIndexToken::SetSheet( sal_Int16 n ) { mnSheet = n; } | |||
1926 | bool FormulaIndexToken::operator==( const FormulaToken& r ) const | |||
1927 | { | |||
1928 | return FormulaToken::operator==( r ) && nIndex == r.GetIndex() && | |||
1929 | mnSheet == r.GetSheet(); | |||
1930 | } | |||
1931 | const OUString& FormulaExternalToken::GetExternal() const { return aExternal; } | |||
1932 | sal_uInt8 FormulaExternalToken::GetByte() const { return nByte; } | |||
1933 | void FormulaExternalToken::SetByte( sal_uInt8 n ) { nByte = n; } | |||
1934 | bool FormulaExternalToken::operator==( const FormulaToken& r ) const | |||
1935 | { | |||
1936 | return FormulaToken::operator==( r ) && nByte == r.GetByte() && | |||
1937 | aExternal == r.GetExternal(); | |||
1938 | } | |||
1939 | ||||
1940 | ||||
1941 | FormulaError FormulaErrorToken::GetError() const { return nError; } | |||
1942 | void FormulaErrorToken::SetError( FormulaError nErr ) { nError = nErr; } | |||
1943 | bool FormulaErrorToken::operator==( const FormulaToken& r ) const | |||
1944 | { | |||
1945 | return FormulaToken::operator==( r ) && | |||
1946 | nError == static_cast< const FormulaErrorToken & >(r).GetError(); | |||
1947 | } | |||
1948 | double FormulaMissingToken::GetDouble() const { return 0.0; } | |||
1949 | ||||
1950 | svl::SharedString FormulaMissingToken::GetString() const | |||
1951 | { | |||
1952 | return svl::SharedString::getEmptyString(); | |||
1953 | } | |||
1954 | ||||
1955 | bool FormulaMissingToken::operator==( const FormulaToken& r ) const | |||
1956 | { | |||
1957 | return FormulaToken::operator==( r ); | |||
1958 | } | |||
1959 | ||||
1960 | ||||
1961 | bool FormulaUnknownToken::operator==( const FormulaToken& r ) const | |||
1962 | { | |||
1963 | return FormulaToken::operator==( r ); | |||
1964 | } | |||
1965 | ||||
1966 | ||||
1967 | } // formula | |||
1968 | ||||
1969 | ||||
1970 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_FORMULA_TOKEN_HXX |
21 | #define INCLUDED_FORMULA_TOKEN_HXX |
22 | |
23 | #include <sal/config.h> |
24 | |
25 | #include <cstring> |
26 | #include <memory> |
27 | #include <vector> |
28 | |
29 | #include <formula/formuladllapi.h> |
30 | #include <formula/opcode.hxx> |
31 | #include <formula/types.hxx> |
32 | #include <formula/paramclass.hxx> |
33 | #include <osl/interlck.h> |
34 | #include <rtl/ustring.hxx> |
35 | #include <sal/types.h> |
36 | #include <svl/sharedstring.hxx> |
37 | |
38 | class ScJumpMatrix; |
39 | class ScMatrix; |
40 | struct ScComplexRefData; |
41 | struct ScSingleRefData; |
42 | enum class FormulaError : sal_uInt16; |
43 | |
44 | namespace formula |
45 | { |
46 | |
47 | enum StackVar : sal_uInt8 |
48 | { |
49 | svByte, |
50 | svDouble, |
51 | svString, |
52 | svSingleRef, |
53 | svDoubleRef, |
54 | svMatrix, |
55 | svIndex, |
56 | svJump, |
57 | svExternal, // Byte + String |
58 | svFAP, // FormulaAutoPilot only, ever exported |
59 | svJumpMatrix, |
60 | svRefList, // ocUnion result |
61 | svEmptyCell, // Result is an empty cell, e.g. in LOOKUP() |
62 | |
63 | svMatrixCell, // Result is a matrix with bells and |
64 | // whistles as needed for _the_ matrix |
65 | // formula result. |
66 | |
67 | svHybridCell, // A temporary condition of a formula |
68 | // cell during import, having a double |
69 | // and/or string result and a formula |
70 | // string to be compiled. |
71 | |
72 | svExternalSingleRef, |
73 | svExternalDoubleRef, |
74 | svExternalName, |
75 | svSingleVectorRef, |
76 | svDoubleVectorRef, |
77 | svError, // error token |
78 | svMissing, // 0 or "" |
79 | svSep, // separator, ocSep, ocOpen, ocClose |
80 | svUnknown // unknown StackType |
81 | }; |
82 | |
83 | // Only to be used for debugging output. No guarantee of stability of the |
84 | // return value. |
85 | |
86 | // Turn this into an operator<< when StackVar becomes a scoped enum |
87 | |
88 | inline std::string StackVarEnumToString(StackVar const e) |
89 | { |
90 | switch (e) |
91 | { |
92 | case svByte: return "Byte"; |
93 | case svDouble: return "Double"; |
94 | case svString: return "String"; |
95 | case svSingleRef: return "SingleRef"; |
96 | case svDoubleRef: return "DoubleRef"; |
97 | case svMatrix: return "Matrix"; |
98 | case svIndex: return "Index"; |
99 | case svJump: return "Jump"; |
100 | case svExternal: return "External"; |
101 | case svFAP: return "FAP"; |
102 | case svJumpMatrix: return "JumpMatrix"; |
103 | case svRefList: return "RefList"; |
104 | case svEmptyCell: return "EmptyCell"; |
105 | case svMatrixCell: return "MatrixCell"; |
106 | case svHybridCell: return "HybridCell"; |
107 | case svExternalSingleRef: return "ExternalSingleRef"; |
108 | case svExternalDoubleRef: return "ExternalDoubleRef"; |
109 | case svExternalName: return "ExternalName"; |
110 | case svSingleVectorRef: return "SingleVectorRef"; |
111 | case svDoubleVectorRef: return "DoubleVectorRef"; |
112 | case svError: return "Error"; |
113 | case svMissing: return "Missing"; |
114 | case svSep: return "Sep"; |
115 | case svUnknown: return "Unknown"; |
116 | } |
117 | std::ostringstream os; |
118 | os << static_cast<int>(e); |
119 | return os.str(); |
120 | } |
121 | |
122 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaToken |
123 | { |
124 | OpCode eOp; |
125 | const StackVar eType; // type of data |
126 | mutable oslInterlockedCount mnRefCnt; // reference count |
127 | |
128 | FormulaToken& operator=( const FormulaToken& ) = delete; |
129 | public: |
130 | FormulaToken( StackVar eTypeP,OpCode e = ocPush ); |
131 | FormulaToken( const FormulaToken& r ); |
132 | |
133 | virtual ~FormulaToken(); |
134 | |
135 | void Delete() { delete this; } |
136 | void DeleteIfZeroRef() { if (mnRefCnt == 0) delete this; } |
137 | StackVar GetType() const { return eType; } |
138 | bool IsFunction() const; // pure functions, no operators |
139 | |
140 | bool IsExternalRef() const; |
141 | bool IsRef() const; |
142 | |
143 | sal_uInt8 GetParamCount() const; |
144 | |
145 | void IncRef() const |
146 | { |
147 | osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1); |
148 | } |
149 | |
150 | void DecRef() const |
151 | { |
152 | if (!osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1)) |
153 | const_cast<FormulaToken*>(this)->Delete(); |
154 | } |
155 | |
156 | oslInterlockedCount GetRef() const { return mnRefCnt; } |
157 | OpCode GetOpCode() const { return eOp; } |
158 | |
159 | bool IsInForceArray() const; |
160 | |
161 | /** |
162 | Dummy methods to avoid switches and casts where possible, |
163 | the real token classes have to override the appropriate method[s]. |
164 | The only methods valid anytime if not overridden are: |
165 | |
166 | - GetByte() since this represents the count of parameters to a function |
167 | which of course is 0 on non-functions. FormulaByteToken and ScExternal do |
168 | override it. |
169 | |
170 | - GetInForceArray() since also this is only used for operators and |
171 | functions and is ParamClass::Unknown for other tokens. |
172 | |
173 | Any other non-overridden method pops up an assertion. |
174 | */ |
175 | |
176 | virtual sal_uInt8 GetByte() const; |
177 | virtual void SetByte( sal_uInt8 n ); |
178 | virtual ParamClass GetInForceArray() const; |
179 | virtual void SetInForceArray( ParamClass c ); |
180 | virtual double GetDouble() const; |
181 | virtual double& GetDoubleAsReference(); |
182 | virtual sal_Int16 GetDoubleType() const; |
183 | virtual void SetDoubleType( sal_Int16 nType ); |
184 | virtual svl::SharedString GetString() const; |
185 | virtual void SetString( const svl::SharedString& rStr ); |
186 | virtual sal_uInt16 GetIndex() const; |
187 | virtual void SetIndex( sal_uInt16 n ); |
188 | virtual sal_Int16 GetSheet() const; |
189 | virtual void SetSheet( sal_Int16 n ); |
190 | virtual short* GetJump() const; |
191 | virtual const OUString& GetExternal() const; |
192 | virtual FormulaToken* GetFAPOrigToken() const; |
193 | virtual FormulaError GetError() const; |
194 | virtual void SetError( FormulaError ); |
195 | |
196 | virtual const ScSingleRefData* GetSingleRef() const; |
197 | virtual ScSingleRefData* GetSingleRef(); |
198 | virtual const ScComplexRefData* GetDoubleRef() const; |
199 | virtual ScComplexRefData* GetDoubleRef(); |
200 | virtual const ScSingleRefData* GetSingleRef2() const; |
201 | virtual ScSingleRefData* GetSingleRef2(); |
202 | virtual const ScMatrix* GetMatrix() const; |
203 | virtual ScMatrix* GetMatrix(); |
204 | virtual ScJumpMatrix* GetJumpMatrix() const; |
205 | virtual const std::vector<ScComplexRefData>* GetRefList() const; |
206 | virtual std::vector<ScComplexRefData>* GetRefList(); |
207 | |
208 | virtual FormulaToken* Clone() const { return new FormulaToken(*this); } |
209 | |
210 | virtual bool TextEqual( const formula::FormulaToken& rToken ) const; |
211 | virtual bool operator==( const FormulaToken& rToken ) const; |
212 | |
213 | /** This is dirty and only the compiler should use it! */ |
214 | struct PrivateAccess { friend class FormulaCompiler; private: PrivateAccess() { } }; |
215 | void NewOpCode( OpCode e, const PrivateAccess& ) { eOp = e; } |
216 | }; |
217 | |
218 | inline void intrusive_ptr_add_ref(const FormulaToken* p) |
219 | { |
220 | p->IncRef(); |
221 | } |
222 | |
223 | inline void intrusive_ptr_release(const FormulaToken* p) |
224 | { |
225 | p->DecRef(); |
226 | } |
227 | |
228 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaByteToken : public FormulaToken |
229 | { |
230 | private: |
231 | sal_uInt8 nByte; |
232 | ParamClass eInForceArray; |
233 | protected: |
234 | FormulaByteToken( OpCode e, sal_uInt8 n, StackVar v, ParamClass c ) : |
235 | FormulaToken( v,e ), nByte( n ), |
236 | eInForceArray( c ) {} |
237 | public: |
238 | FormulaByteToken( OpCode e, sal_uInt8 n, ParamClass c ) : |
239 | FormulaToken( svByte,e ), nByte( n ), |
240 | eInForceArray( c ) {} |
241 | FormulaByteToken( OpCode e, sal_uInt8 n ) : |
242 | FormulaToken( svByte,e ), nByte( n ), |
243 | eInForceArray( ParamClass::Unknown ) {} |
244 | FormulaByteToken( OpCode e ) : |
245 | FormulaToken( svByte,e ), nByte( 0 ), |
246 | eInForceArray( ParamClass::Unknown ) {} |
247 | FormulaByteToken( const FormulaByteToken& r ) : |
248 | FormulaToken( r ), nByte( r.nByte ), |
249 | eInForceArray( r.eInForceArray ) {} |
250 | |
251 | virtual FormulaToken* Clone() const override { return new FormulaByteToken(*this); } |
252 | virtual sal_uInt8 GetByte() const override; |
253 | virtual void SetByte( sal_uInt8 n ) override; |
254 | virtual ParamClass GetInForceArray() const override; |
255 | virtual void SetInForceArray( ParamClass c ) override; |
256 | virtual bool operator==( const FormulaToken& rToken ) const override; |
257 | }; |
258 | |
259 | |
260 | // A special token for the FormulaAutoPilot only. Keeps a reference pointer of |
261 | // the token of which it was created for comparison. |
262 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaFAPToken final : public FormulaByteToken |
263 | { |
264 | private: |
265 | FormulaTokenRef pOrigToken; |
266 | public: |
267 | FormulaFAPToken( OpCode e, sal_uInt8 n, FormulaToken* p ) : |
268 | FormulaByteToken( e, n, svFAP, ParamClass::Unknown ), |
269 | pOrigToken( p ) {} |
270 | FormulaFAPToken( const FormulaFAPToken& r ) : |
271 | FormulaByteToken( r ), pOrigToken( r.pOrigToken ) {} |
272 | |
273 | virtual FormulaToken* Clone() const override { return new FormulaFAPToken(*this); } |
274 | virtual FormulaToken* GetFAPOrigToken() const override; |
275 | virtual bool operator==( const FormulaToken& rToken ) const override; |
276 | }; |
277 | |
278 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaDoubleToken : public FormulaToken |
279 | { |
280 | private: |
281 | double fDouble; |
282 | public: |
283 | FormulaDoubleToken( double f ) : |
284 | FormulaToken( svDouble ), fDouble( f ) {} |
285 | FormulaDoubleToken( const FormulaDoubleToken& r ) : |
286 | FormulaToken( r ), fDouble( r.fDouble ) {} |
287 | |
288 | virtual FormulaToken* Clone() const override { return new FormulaDoubleToken(*this); } |
289 | virtual double GetDouble() const override; |
290 | virtual double& GetDoubleAsReference() override; |
291 | virtual sal_Int16 GetDoubleType() const override; ///< always returns 0 for "not typed" |
292 | virtual bool operator==( const FormulaToken& rToken ) const override; |
293 | }; |
294 | |
295 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaTypedDoubleToken final : public FormulaDoubleToken |
296 | { |
297 | private: |
298 | sal_Int16 mnType; /**< Can hold, for example, a value |
299 | of SvNumFormatType, or by |
300 | contract any other |
301 | classification. */ |
302 | public: |
303 | FormulaTypedDoubleToken( double f, sal_Int16 nType ) : |
304 | FormulaDoubleToken( f ), mnType( nType ) {} |
305 | FormulaTypedDoubleToken( const FormulaTypedDoubleToken& r ) : |
306 | FormulaDoubleToken( r ), mnType( r.mnType ) {} |
307 | |
308 | virtual FormulaToken* Clone() const override { return new FormulaTypedDoubleToken(*this); } |
309 | virtual sal_Int16 GetDoubleType() const override; |
310 | virtual void SetDoubleType( sal_Int16 nType ) override; |
311 | virtual bool operator==( const FormulaToken& rToken ) const override; |
312 | }; |
313 | |
314 | |
315 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaStringToken final : public FormulaToken |
316 | { |
317 | svl::SharedString maString; |
318 | public: |
319 | FormulaStringToken( const svl::SharedString& r ); |
320 | FormulaStringToken( const FormulaStringToken& r ); |
321 | |
322 | virtual FormulaToken* Clone() const override; |
323 | virtual svl::SharedString GetString() const override; |
324 | virtual void SetString( const svl::SharedString& rStr ) override; |
325 | virtual bool operator==( const FormulaToken& rToken ) const override; |
326 | }; |
327 | |
328 | |
329 | /** Identical to FormulaStringToken, but with explicit OpCode instead of implicit |
330 | ocPush, and an optional sal_uInt8 for ocBad tokens. */ |
331 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaStringOpToken final : public FormulaByteToken |
332 | { |
333 | svl::SharedString maString; |
334 | public: |
335 | FormulaStringOpToken( OpCode e, const svl::SharedString& r ); |
336 | FormulaStringOpToken( const FormulaStringOpToken& r ); |
337 | |
338 | virtual FormulaToken* Clone() const override; |
339 | virtual svl::SharedString GetString() const override; |
340 | virtual void SetString( const svl::SharedString& rStr ) override; |
341 | virtual bool operator==( const FormulaToken& rToken ) const override; |
342 | }; |
343 | |
344 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaIndexToken final : public FormulaToken |
345 | { |
346 | private: |
347 | sal_uInt16 nIndex; |
348 | sal_Int16 mnSheet; |
349 | public: |
350 | FormulaIndexToken( OpCode e, sal_uInt16 n, sal_Int16 nSheet = -1 ) : |
351 | FormulaToken( svIndex, e ), nIndex( n ), mnSheet( nSheet ) {} |
352 | FormulaIndexToken( const FormulaIndexToken& r ) : |
353 | FormulaToken( r ), nIndex( r.nIndex ), mnSheet( r.mnSheet ) {} |
354 | |
355 | virtual FormulaToken* Clone() const override { return new FormulaIndexToken(*this); } |
356 | virtual sal_uInt16 GetIndex() const override; |
357 | virtual void SetIndex( sal_uInt16 n ) override; |
358 | virtual sal_Int16 GetSheet() const override; |
359 | virtual void SetSheet( sal_Int16 n ) override; |
360 | virtual bool operator==( const FormulaToken& rToken ) const override; |
361 | }; |
362 | |
363 | |
364 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaExternalToken final : public FormulaToken |
365 | { |
366 | private: |
367 | OUString aExternal; |
368 | sal_uInt8 nByte; |
369 | public: |
370 | FormulaExternalToken( OpCode e, sal_uInt8 n, const OUString& r ) : |
371 | FormulaToken( svExternal, e ), aExternal( r ), |
372 | nByte( n ) {} |
373 | FormulaExternalToken( OpCode e, const OUString& r ) : |
374 | FormulaToken(svExternal, e ), aExternal( r ), |
375 | nByte( 0 ) {} |
376 | FormulaExternalToken( const FormulaExternalToken& r ) : |
377 | FormulaToken( r ), aExternal( r.aExternal ), |
378 | nByte( r.nByte ) {} |
379 | |
380 | virtual FormulaToken* Clone() const override { return new FormulaExternalToken(*this); } |
381 | virtual const OUString& GetExternal() const override; |
382 | virtual sal_uInt8 GetByte() const override; |
383 | virtual void SetByte( sal_uInt8 n ) override; |
384 | virtual bool operator==( const FormulaToken& rToken ) const override; |
385 | }; |
386 | |
387 | |
388 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaMissingToken final : public FormulaToken |
389 | { |
390 | public: |
391 | FormulaMissingToken() : |
392 | FormulaToken( svMissing,ocMissing ) {} |
393 | FormulaMissingToken( const FormulaMissingToken& r ) : |
394 | FormulaToken( r ) {} |
395 | |
396 | virtual FormulaToken* Clone() const override { return new FormulaMissingToken(*this); } |
397 | virtual double GetDouble() const override; |
398 | virtual svl::SharedString GetString() const override; |
399 | virtual bool operator==( const FormulaToken& rToken ) const override; |
400 | }; |
401 | |
402 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaJumpToken final : public FormulaToken |
403 | { |
404 | private: |
405 | std::unique_ptr<short[]> |
406 | pJump; |
407 | ParamClass eInForceArray; |
408 | public: |
409 | FormulaJumpToken( OpCode e, short const * p ) : |
410 | FormulaToken( formula::svJump , e), |
411 | eInForceArray( ParamClass::Unknown) |
412 | { |
413 | pJump.reset( new short[ p[0] + 1 ] ); |
414 | memcpy( pJump.get(), p, (p[0] + 1) * sizeof(short) ); |
415 | } |
416 | FormulaJumpToken( const FormulaJumpToken& r ) : |
417 | FormulaToken( r ), |
418 | eInForceArray( r.eInForceArray) |
419 | { |
420 | pJump.reset( new short[ r.pJump[0] + 1 ] ); |
421 | memcpy( pJump.get(), r.pJump.get(), (r.pJump[0] + 1) * sizeof(short) ); |
422 | } |
423 | virtual ~FormulaJumpToken() override; |
424 | virtual short* GetJump() const override; |
425 | virtual bool operator==( const formula::FormulaToken& rToken ) const override; |
426 | virtual FormulaToken* Clone() const override { return new FormulaJumpToken(*this); } |
427 | virtual ParamClass GetInForceArray() const override; |
428 | virtual void SetInForceArray( ParamClass c ) override; |
429 | }; |
430 | |
431 | |
432 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaUnknownToken final : public FormulaToken |
433 | { |
434 | public: |
435 | FormulaUnknownToken( OpCode e ) : |
436 | FormulaToken( svUnknown, e ) {} |
437 | FormulaUnknownToken( const FormulaUnknownToken& r ) : |
438 | FormulaToken( r ) {} |
439 | |
440 | virtual FormulaToken* Clone() const override { return new FormulaUnknownToken(*this); } |
441 | virtual bool operator==( const FormulaToken& rToken ) const override; |
442 | }; |
443 | |
444 | |
445 | class FORMULA_DLLPUBLIC__attribute__ ((visibility("default"))) FormulaErrorToken final : public FormulaToken |
446 | { |
447 | FormulaError nError; |
448 | public: |
449 | FormulaErrorToken( FormulaError nErr ) : |
450 | FormulaToken( svError ), nError( nErr) {} |
451 | FormulaErrorToken( const FormulaErrorToken& r ) : |
452 | FormulaToken( r ), nError( r.nError) {} |
453 | |
454 | virtual FormulaToken* Clone() const override { return new FormulaErrorToken(*this); } |
455 | virtual FormulaError GetError() const override; |
456 | virtual void SetError( FormulaError nErr ) override; |
457 | virtual bool operator==( const FormulaToken& rToken ) const override; |
458 | }; |
459 | |
460 | |
461 | } // formula |
462 | |
463 | |
464 | #endif |
465 | |
466 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |