Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #if defined(MACOSX)
30 : : #include <stdlib.h>
31 : : #endif
32 : :
33 : : #include <calc.hxx>
34 : : #include <cctype>
35 : : #include <cfloat>
36 : : #include <climits>
37 : : #include <comphelper/processfactory.hxx>
38 : : #include <comphelper/string.hxx>
39 : : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
40 : : #include <cstdlib>
41 : : #include <dbfld.hxx>
42 : : #include <dbmgr.hxx>
43 : : #include <docfld.hxx>
44 : : #include <docstat.hxx>
45 : : #include <doc.hxx>
46 : : #include <editeng/langitem.hxx>
47 : : #include <editeng/scripttypeitem.hxx>
48 : : #include <editeng/unolingu.hxx>
49 : : #include <expfld.hxx>
50 : : #include <hintids.hxx>
51 : : #include <osl/diagnose.hxx>
52 : : #include <rtl/math.hxx>
53 : : #include <shellres.hxx>
54 : : #include <svl/zforlist.hxx>
55 : : #include <swmodule.hxx>
56 : : #include <swtypes.hxx>
57 : : #include <unotools/charclass.hxx>
58 : : #include <unotools/localedatawrapper.hxx>
59 : : #include <unotools/useroptions.hxx>
60 : : #include <usrfld.hxx>
61 : : #include <viewsh.hxx>
62 : :
63 : : using namespace ::com::sun::star;
64 : :
65 : : // shortcut
66 : : #define RESOURCE ViewShell::GetShellRes()
67 : :
68 : : const sal_Char sCalc_Add[] = "add";
69 : : const sal_Char sCalc_Sub[] = "sub";
70 : : const sal_Char sCalc_Mul[] = "mul";
71 : : const sal_Char sCalc_Div[] = "div";
72 : : const sal_Char sCalc_Phd[] = "phd";
73 : : const sal_Char sCalc_Sqrt[] = "sqrt";
74 : : const sal_Char sCalc_Pow[] = "pow";
75 : : const sal_Char sCalc_Or[] = "or";
76 : : const sal_Char sCalc_Xor[] = "xor";
77 : : const sal_Char sCalc_And[] = "and";
78 : : const sal_Char sCalc_Not[] = "not";
79 : : const sal_Char sCalc_Eq[] = "eq";
80 : : const sal_Char sCalc_Neq[] = "neq";
81 : : const sal_Char sCalc_Leq[] = "leq";
82 : : const sal_Char sCalc_Geq[] = "geq";
83 : : const sal_Char sCalc_L[] = "l";
84 : : const sal_Char sCalc_G[] = "g";
85 : : const sal_Char sCalc_Sum[] = "sum";
86 : : const sal_Char sCalc_Mean[] = "mean";
87 : : const sal_Char sCalc_Min[] = "min";
88 : : const sal_Char sCalc_Max[] = "max";
89 : : const sal_Char sCalc_Sin[] = "sin";
90 : : const sal_Char sCalc_Cos[] = "cos";
91 : : const sal_Char sCalc_Tan[] = "tan";
92 : : const sal_Char sCalc_Asin[] = "asin";
93 : : const sal_Char sCalc_Acos[] = "acos";
94 : : const sal_Char sCalc_Atan[] = "atan";
95 : : const sal_Char sCalc_Round[]= "round";
96 : : const sal_Char sCalc_Date[] = "date";
97 : :
98 : : // ATTENTION: sorted list of all operators
99 : : struct _CalcOp
100 : : {
101 : : union{
102 : : const sal_Char* pName;
103 : : const String* pUName;
104 : : };
105 : : SwCalcOper eOp;
106 : : };
107 : :
108 : : _CalcOp const aOpTable[] = {
109 : : /* ACOS */ {{sCalc_Acos}, CALC_ACOS}, // Arc cosine
110 : : /* ADD */ {{sCalc_Add}, CALC_PLUS}, // Addition
111 : : /* AND */ {{sCalc_And}, CALC_AND}, // log. AND
112 : : /* ASIN */ {{sCalc_Asin}, CALC_ASIN}, // Arc sine
113 : : /* ATAN */ {{sCalc_Atan}, CALC_ATAN}, // Arc tangent
114 : : /* COS */ {{sCalc_Cos}, CALC_COS}, // Cosine
115 : : /* DATE */ {{sCalc_Date}, CALC_DATE}, // Date
116 : : /* DIV */ {{sCalc_Div}, CALC_DIV}, // Division
117 : : /* EQ */ {{sCalc_Eq}, CALC_EQ}, // Equality
118 : : /* G */ {{sCalc_G}, CALC_GRE}, // Greater than
119 : : /* GEQ */ {{sCalc_Geq}, CALC_GEQ}, // Greater or equal
120 : : /* L */ {{sCalc_L}, CALC_LES}, // Less than
121 : : /* LEQ */ {{sCalc_Leq}, CALC_LEQ}, // Less or equal
122 : : /* MAX */ {{sCalc_Max}, CALC_MAX}, // Maximum value
123 : : /* MEAN */ {{sCalc_Mean}, CALC_MEAN}, // Mean
124 : : /* MIN */ {{sCalc_Min}, CALC_MIN}, // Minimum value
125 : : /* MUL */ {{sCalc_Mul}, CALC_MUL}, // Multiplication
126 : : /* NEQ */ {{sCalc_Neq}, CALC_NEQ}, // Not equal
127 : : /* NOT */ {{sCalc_Not}, CALC_NOT}, // log. NOT
128 : : /* OR */ {{sCalc_Or}, CALC_OR}, // log. OR
129 : : /* PHD */ {{sCalc_Phd}, CALC_PHD}, // Percentage
130 : : /* POW */ {{sCalc_Pow}, CALC_POW}, // Exponentiation
131 : : /* ROUND */ {{sCalc_Round}, CALC_ROUND}, // Rounding
132 : : /* SIN */ {{sCalc_Sin}, CALC_SIN}, // Sine
133 : : /* SQRT */ {{sCalc_Sqrt}, CALC_SQRT}, // Square root
134 : : /* SUB */ {{sCalc_Sub}, CALC_MINUS}, // Subtraction
135 : : /* SUM */ {{sCalc_Sum}, CALC_SUM}, // Sum
136 : : /* TAN */ {{sCalc_Tan}, CALC_TAN}, // Tangent
137 : : /* XOR */ {{sCalc_Xor}, CALC_XOR} // log. XOR
138 : : };
139 : :
140 : : double const nRoundVal[] = {
141 : : 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6,
142 : : 0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,
143 : : 0.5e-15,0.5e-16
144 : : };
145 : :
146 : : double const nKorrVal[] = {
147 : : 9, 9e-1, 9e-2, 9e-3, 9e-4, 9e-5, 9e-6, 9e-7, 9e-8,
148 : : 9e-9, 9e-10, 9e-11, 9e-12, 9e-13, 9e-14
149 : : };
150 : :
151 : : // First character may be any alphabetic or underscore.
152 : : const sal_Int32 coStartFlags =
153 : : i18n::KParseTokens::ANY_LETTER_OR_NUMBER |
154 : : i18n::KParseTokens::ASC_UNDERSCORE |
155 : : i18n::KParseTokens::IGNORE_LEADING_WS;
156 : :
157 : : // Continuing characters may be any alphanumeric, underscore, or dot.
158 : : const sal_Int32 coContFlags =
159 : : ( coStartFlags | i18n::KParseTokens::ASC_DOT )
160 : : & ~i18n::KParseTokens::IGNORE_LEADING_WS;
161 : :
162 : : extern "C" {
163 : 150 : static int SAL_CALL OperatorCompare( const void *pFirst, const void *pSecond)
164 : : {
165 : 150 : int nRet = 0;
166 [ + - ]: 150 : if( CALC_NAME == ((_CalcOp*)pFirst)->eOp )
167 : : {
168 [ - + ]: 150 : if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
169 : : nRet = ((_CalcOp*)pFirst)->pUName->CompareTo(
170 : 0 : *((_CalcOp*)pSecond)->pUName );
171 : : else
172 : : nRet = ((_CalcOp*)pFirst)->pUName->CompareToAscii(
173 : 150 : ((_CalcOp*)pSecond)->pName );
174 : : }
175 : : else
176 : : {
177 [ # # ]: 0 : if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
178 : : nRet = -1 * ((_CalcOp*)pSecond)->pUName->CompareToAscii(
179 : 0 : ((_CalcOp*)pFirst)->pName );
180 : : else
181 : : nRet = strcmp( ((_CalcOp*)pFirst)->pName,
182 : 0 : ((_CalcOp*)pSecond)->pName );
183 : : }
184 : 150 : return nRet;
185 : : }
186 : : }// extern "C"
187 : :
188 : 30 : _CalcOp* FindOperator( const String& rSrch )
189 : : {
190 : : _CalcOp aSrch;
191 : 30 : aSrch.pUName = &rSrch;
192 : 30 : aSrch.eOp = CALC_NAME;
193 : :
194 : : return (_CalcOp*)bsearch( (void*) &aSrch,
195 : : (void*) aOpTable,
196 : : sizeof( aOpTable ) / sizeof( _CalcOp ),
197 : : sizeof( _CalcOp ),
198 [ + - ]: 30 : OperatorCompare );
199 : : }
200 : :
201 : 84 : SwHash* Find( const String& rStr, SwHash** ppTable,
202 : : sal_uInt16 nTblSize, sal_uInt16* pPos )
203 : : {
204 : 84 : sal_uLong ii = 0;
205 [ + + ]: 747 : for( xub_StrLen n = 0; n < rStr.Len(); ++n )
206 : : {
207 : 663 : ii = ii << 1 ^ rStr.GetChar( n );
208 : : }
209 : 84 : ii %= nTblSize;
210 : :
211 [ + - ]: 84 : if( pPos )
212 : 84 : *pPos = (sal_uInt16)ii;
213 : :
214 [ + + ]: 104 : for( SwHash* pEntry = *(ppTable+ii); pEntry; pEntry = pEntry->pNext )
215 : : {
216 [ - + ]: 20 : if( rStr == pEntry->aStr )
217 : : {
218 : 0 : return pEntry;
219 : : }
220 : : }
221 : 84 : return 0;
222 : : }
223 : :
224 : 24 : inline LanguageType GetDocAppScriptLang( SwDoc& rDoc )
225 : : {
226 : : return ((SvxLanguageItem&)rDoc.GetDefault(
227 : : GetWhichOfScript( RES_CHRATR_LANGUAGE,
228 : 24 : GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() ))
229 : 24 : )).GetLanguage();
230 : : }
231 : :
232 : 0 : double lcl_ConvertToDateValue( SwDoc& rDoc, sal_Int32 nDate )
233 : : {
234 : 0 : double nRet = 0;
235 : 0 : SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter();
236 [ # # ]: 0 : if( pFormatter )
237 : : {
238 [ # # ]: 0 : Date* pNull = pFormatter->GetNullDate();
239 : 0 : Date aDate( nDate >> 24, (nDate& 0x00FF0000) >> 16, nDate& 0x0000FFFF );
240 [ # # ]: 0 : nRet = aDate - *pNull;
241 : : }
242 : 0 : return nRet;
243 : : }
244 : :
245 : 24 : SwCalc::SwCalc( SwDoc& rD )
246 : : : aErrExpr( aEmptyStr, SwSbxValue(), 0 ),
247 : : rDoc( rD ),
248 [ + - ]: 24 : pLclData( m_aSysLocale.GetLocaleDataPtr() ),
249 [ + - ]: 24 : pCharClass( &GetAppCharClass() ),
250 : : nListPor( 0 ),
251 [ + - ][ + - ]: 24 : eError( CALC_NOERR )
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
252 : : {
253 [ + - ]: 24 : aErrExpr.aStr.AssignAscii( "~C_ERR~" );
254 : 24 : memset( VarTable, 0, sizeof(VarTable) );
255 [ + - ]: 24 : LanguageType eLang = GetDocAppScriptLang( rDoc );
256 : :
257 [ + - ][ + - ]: 42 : if( eLang != SvxLocaleToLanguage( pLclData->getLocale() ) ||
[ + + ][ - + ]
[ + + ]
258 [ + - ][ + - ]: 18 : eLang != SvxLocaleToLanguage( pCharClass->getLocale() ) )
259 : : {
260 [ + - ]: 6 : ::com::sun::star::lang::Locale aLocale( SvxCreateLocale( eLang ));
261 : : ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(
262 [ + - ]: 6 : ::comphelper::getProcessServiceFactory() );
263 [ + - ][ + - ]: 6 : pCharClass = new CharClass( xMSF, aLocale );
264 [ + - ][ + - ]: 6 : pLclData = new LocaleDataWrapper( xMSF, aLocale );
265 : : }
266 : :
267 [ + - ][ + - ]: 24 : sCurrSym = comphelper::string::strip(pLclData->getCurrSymbol(), ' ');
[ + - ]
268 [ + - ][ + - ]: 24 : sCurrSym = pCharClass->lowercase( sCurrSym );
[ + - ]
269 : :
270 : : static sal_Char const
271 : : sNType0[] = "false",
272 : : sNType1[] = "true",
273 : : sNType2[] = "pi",
274 : : sNType3[] = "e",
275 : : sNType4[] = "tables",
276 : : sNType5[] = "graf",
277 : : sNType6[] = "ole",
278 : : sNType7[] = "page",
279 : : sNType8[] = "para",
280 : : sNType9[] = "word",
281 : : sNType10[]= "char",
282 : :
283 : : sNType11[] = "user_firstname" ,
284 : : sNType12[] = "user_lastname" ,
285 : : sNType13[] = "user_initials" ,
286 : : sNType14[] = "user_company" ,
287 : : sNType15[] = "user_street" ,
288 : : sNType16[] = "user_country" ,
289 : : sNType17[] = "user_zipcode" ,
290 : : sNType18[] = "user_city" ,
291 : : sNType19[] = "user_title" ,
292 : : sNType20[] = "user_position" ,
293 : : sNType21[] = "user_tel_work" ,
294 : : sNType22[] = "user_tel_home" ,
295 : : sNType23[] = "user_fax" ,
296 : : sNType24[] = "user_email" ,
297 : : sNType25[] = "user_state" ,
298 : : sNType26[] = "graph"
299 : : ;
300 : : static const sal_Char* const sNTypeTab[ 27 ] =
301 : : {
302 : : sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
303 : : sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
304 : : sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
305 : : sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
306 : : sNType24,
307 : :
308 : : // those have two HashIds
309 : : sNType25, sNType26
310 : : };
311 : : static sal_uInt16 const aHashValue[ 27 ] =
312 : : {
313 : : 34, 38, 43, 7, 18, 32, 22, 29, 30, 33, 3,
314 : : 28, 24, 40, 9, 11, 26, 45, 4, 23, 36, 44, 19, 5, 1,
315 : : // those have two HashIds
316 : : 11, 38
317 : : };
318 : : static sal_uInt16 const aAdrToken[ 12 ] =
319 : : {
320 : : USER_OPT_COMPANY, USER_OPT_STREET, USER_OPT_COUNTRY, USER_OPT_ZIP,
321 : : USER_OPT_CITY, USER_OPT_TITLE, USER_OPT_POSITION, USER_OPT_TELEPHONEWORK,
322 : : USER_OPT_TELEPHONEHOME, USER_OPT_FAX, USER_OPT_EMAIL, USER_OPT_STATE
323 : : };
324 : :
325 : : static sal_uInt16 SwDocStat::* const aDocStat1[ 3 ] =
326 : : {
327 : : &SwDocStat::nTbl, &SwDocStat::nGrf, &SwDocStat::nOLE
328 : : };
329 : : static sal_uLong SwDocStat::* const aDocStat2[ 4 ] =
330 : : {
331 : : &SwDocStat::nPage, &SwDocStat::nPara,
332 : : &SwDocStat::nWord, &SwDocStat::nChar
333 : : };
334 : :
335 : : #if TBLSZ != 47
336 : : #error Did you adjust all hash values?
337 : : #endif
338 : :
339 [ + - ]: 24 : const SwDocStat& rDocStat = rDoc.GetDocStat();
340 : :
341 [ + - ]: 24 : SwSbxValue nVal;
342 [ + - ]: 24 : String sTmpStr;
343 : : sal_uInt16 n;
344 : :
345 [ + + ]: 624 : for( n = 0; n < 25; ++n )
346 : : {
347 [ + - ]: 600 : sTmpStr.AssignAscii( sNTypeTab[ n ] );
348 [ + - ][ + - ]: 600 : VarTable[ aHashValue[ n ] ] = new SwCalcExp( sTmpStr, nVal, 0 );
349 : : }
350 : :
351 [ + - ]: 24 : ((SwCalcExp*)VarTable[ aHashValue[ 0 ] ])->nValue.PutBool( sal_False );
352 [ + - ]: 24 : ((SwCalcExp*)VarTable[ aHashValue[ 1 ] ])->nValue.PutBool( sal_True );
353 [ + - ]: 24 : ((SwCalcExp*)VarTable[ aHashValue[ 2 ] ])->nValue.PutDouble( F_PI );
354 [ + - ]: 24 : ((SwCalcExp*)VarTable[ aHashValue[ 3 ] ])->nValue.PutDouble( 2.7182818284590452354 );
355 : :
356 [ + + ]: 96 : for( n = 0; n < 3; ++n )
357 [ + - ]: 72 : ((SwCalcExp*)VarTable[ aHashValue[ n + 4 ] ])->nValue.PutLong( rDocStat.*aDocStat1[ n ] );
358 [ + + ]: 120 : for( n = 0; n < 4; ++n )
359 [ + - ]: 96 : ((SwCalcExp*)VarTable[ aHashValue[ n + 7 ] ])->nValue.PutLong( rDocStat.*aDocStat2[ n ] );
360 : :
361 [ + - ][ + - ]: 24 : SvtUserOptions& rUserOptions = SW_MOD()->GetUserOptions();
362 : :
363 [ + - ][ + - ]: 24 : ((SwCalcExp*)VarTable[ aHashValue[ 11 ] ])->nValue.PutString( (String)rUserOptions.GetFirstName() );
[ + - ][ + - ]
[ + - ]
364 [ + - ][ + - ]: 24 : ((SwCalcExp*)VarTable[ aHashValue[ 12 ] ])->nValue.PutString( (String)rUserOptions.GetLastName() );
[ + - ][ + - ]
[ + - ]
365 [ + - ][ + - ]: 24 : ((SwCalcExp*)VarTable[ aHashValue[ 13 ] ])->nValue.PutString( (String)rUserOptions.GetID() );
[ + - ][ + - ]
[ + - ]
366 : :
367 [ + + ]: 288 : for( n = 0; n < 11; ++n )
368 : 528 : ((SwCalcExp*)VarTable[ aHashValue[ n + 14 ] ])->nValue.PutString(
369 [ + - ][ + - ]: 264 : (String)rUserOptions.GetToken( aAdrToken[ n ] ));
[ + - ][ + - ]
[ + - ]
370 : :
371 [ + - ][ + - ]: 24 : nVal.PutString( (String)rUserOptions.GetToken( aAdrToken[ 11 ] ));
[ + - ][ + - ]
[ + - ]
372 [ + - ]: 24 : sTmpStr.AssignAscii( sNTypeTab[ 25 ] );
373 [ + - ][ + - ]: 24 : VarTable[ aHashValue[ 25 ] ]->pNext = new SwCalcExp( sTmpStr, nVal, 0 );
[ + - ][ + - ]
374 : :
375 : 24 : } // SwCalc::SwCalc
376 : :
377 [ + - ][ + - ]: 24 : SwCalc::~SwCalc()
[ + - ][ + - ]
[ + - ][ + - ]
378 : : {
379 [ + + ]: 1152 : for( sal_uInt16 n = 0; n < TBLSZ; ++n )
380 [ + + ][ + - ]: 1128 : delete VarTable[n];
381 : :
382 [ + - ][ + + ]: 24 : if( pLclData != m_aSysLocale.GetLocaleDataPtr() )
383 [ + - ][ + - ]: 6 : delete pLclData;
384 [ + - ][ + + ]: 24 : if( pCharClass != &GetAppCharClass() )
385 [ + - ][ + - ]: 6 : delete pCharClass;
386 : 24 : }
387 : :
388 : 24 : SwSbxValue SwCalc::Calculate( const String& rStr )
389 : : {
390 : 24 : eError = CALC_NOERR;
391 : 24 : SwSbxValue nResult;
392 : :
393 [ - + ]: 24 : if( !rStr.Len() )
394 : 0 : return nResult;
395 : :
396 : 24 : nListPor = 0;
397 : 24 : eCurrListOper = CALC_PLUS; // default: sum
398 : :
399 [ + - ]: 24 : sCommand = rStr;
400 : 24 : nCommandPos = 0;
401 : :
402 [ + - ][ + + ]: 48 : while( (eCurrOper = GetToken()) != CALC_ENDCALC && eError == CALC_NOERR )
[ + - ][ + + ]
403 [ + - ][ + - ]: 24 : nResult = Expr();
[ + - ]
404 : :
405 [ - + ]: 24 : if( eError )
406 [ # # ]: 0 : nResult.PutDouble( DBL_MAX );
407 : :
408 : 24 : return nResult;
409 : : }
410 : :
411 : : //TODO: provide documentation
412 : : /** ???
413 : :
414 : : @param rVal ???
415 : : @param bRound In previous times <bRound> had a default value of <sal_True>.
416 : : There it should be only changed when calculating table cells,
417 : : so that no rounding errors would occur while composing a formula.
418 : : Now this parameter is ignored.
419 : : @return ???
420 : : */
421 : 0 : String SwCalc::GetStrResult( const SwSbxValue& rVal, sal_Bool bRound )
422 : : {
423 [ # # ]: 0 : if( !rVal.IsDouble() )
424 : 0 : return rVal.GetString();
425 : :
426 : 0 : return GetStrResult( rVal.GetDouble(), bRound );
427 : : }
428 : :
429 : 0 : String SwCalc::GetStrResult( double nValue, sal_Bool )
430 : : {
431 [ # # ]: 0 : if( nValue >= DBL_MAX )
432 [ # # # # : 0 : switch( eError )
# # # # ]
433 : : {
434 [ # # ][ # # ]: 0 : case CALC_SYNTAX : return RESOURCE->aCalc_Syntax;
435 [ # # ][ # # ]: 0 : case CALC_ZERODIV : return RESOURCE->aCalc_ZeroDiv;
436 [ # # ][ # # ]: 0 : case CALC_BRACK : return RESOURCE->aCalc_Brack;
437 [ # # ][ # # ]: 0 : case CALC_POWERR : return RESOURCE->aCalc_Pow;
438 [ # # ][ # # ]: 0 : case CALC_VARNFND : return RESOURCE->aCalc_VarNFnd;
439 [ # # ][ # # ]: 0 : case CALC_OVERFLOW : return RESOURCE->aCalc_Overflow;
440 [ # # ][ # # ]: 0 : case CALC_WRONGTIME : return RESOURCE->aCalc_WrongTime;
441 [ # # ][ # # ]: 0 : default : return RESOURCE->aCalc_Default;
442 : : }
443 : :
444 : 0 : sal_uInt16 nDec = 15;
445 : : String aRetStr( ::rtl::math::doubleToUString(
446 : : nValue,
447 : : rtl_math_StringFormat_Automatic,
448 : : nDec,
449 [ # # ]: 0 : pLclData->getNumDecimalSep()[0],
450 [ # # ]: 0 : true ));
451 [ # # ][ # # ]: 0 : return aRetStr;
452 : : }
453 : :
454 : 0 : SwCalcExp* SwCalc::VarInsert( const String &rStr )
455 : : {
456 [ # # ][ # # ]: 0 : String aStr = pCharClass->lowercase( rStr );
[ # # ]
457 [ # # ][ # # ]: 0 : return VarLook( aStr, 1 );
458 : : }
459 : :
460 : 24 : SwCalcExp* SwCalc::VarLook( const String& rStr, sal_uInt16 ins )
461 : : {
462 : 24 : aErrExpr.nValue.SetVoidValue(false);
463 : :
464 : 24 : sal_uInt16 ii = 0;
465 [ + - ][ + - ]: 24 : String aStr = pCharClass->lowercase( rStr );
[ + - ]
466 : :
467 [ + - ]: 24 : SwHash* pFnd = Find( aStr, VarTable, TBLSZ, &ii );
468 : :
469 [ + - ]: 24 : if( !pFnd )
470 : : {
471 : : // then check doc
472 [ + - ]: 24 : SwHash** ppDocTbl = rDoc.GetUpdtFlds().GetFldTypeTable();
473 [ + + ]: 30 : for( SwHash* pEntry = *(ppDocTbl+ii); pEntry; pEntry = pEntry->pNext )
474 : : {
475 [ + - ][ + - ]: 6 : if( aStr == pEntry->aStr )
476 : : {
477 : : // then insert here
478 : : pFnd = new SwCalcExp( aStr, SwSbxValue(),
479 [ + - ][ + - ]: 6 : ((SwCalcFldType*)pEntry)->pFldType );
[ + - ][ + - ]
480 : 6 : pFnd->pNext = *(VarTable+ii);
481 : 6 : *(VarTable+ii) = pFnd;
482 : 6 : break;
483 : : }
484 : : }
485 : : }
486 : :
487 [ + + ]: 24 : if( pFnd )
488 : : {
489 : 6 : SwCalcExp* pFndExp = (SwCalcExp*)pFnd;
490 : :
491 [ + - ][ + - ]: 6 : if( pFndExp->pFldType && pFndExp->pFldType->Which() == RES_USERFLD )
[ + - ]
492 : : {
493 : 6 : SwUserFieldType* pUFld = (SwUserFieldType*)pFndExp->pFldType;
494 [ + - ]: 6 : if( nsSwGetSetExpType::GSE_STRING & pUFld->GetType() )
495 : : {
496 [ + - ][ + - ]: 6 : pFndExp->nValue.PutString( pUFld->GetContent() );
[ + - ][ + - ]
497 : : }
498 [ # # ]: 0 : else if( !pUFld->IsValid() )
499 : : {
500 : : // Save the current values...
501 : 0 : sal_uInt16 nOld_ListPor = nListPor;
502 [ # # ]: 0 : SwSbxValue nOld_LastLeft = nLastLeft;
503 [ # # ]: 0 : SwSbxValue nOld_NumberValue = nNumberValue;
504 : 0 : xub_StrLen nOld_CommandPos = nCommandPos;
505 : 0 : SwCalcOper eOld_CurrOper = eCurrOper;
506 : 0 : SwCalcOper eOld_CurrListOper = eCurrListOper;
507 : :
508 [ # # ][ # # ]: 0 : pFndExp->nValue.PutDouble( pUFld->GetValue( *this ) );
509 : :
510 : : // ...and write them back.
511 : 0 : nListPor = nOld_ListPor;
512 [ # # ]: 0 : nLastLeft = nOld_LastLeft;
513 [ # # ]: 0 : nNumberValue = nOld_NumberValue;
514 : 0 : nCommandPos = nOld_CommandPos;
515 : 0 : eCurrOper = eOld_CurrOper;
516 [ # # ][ # # ]: 0 : eCurrListOper = eOld_CurrListOper;
517 : : }
518 : : else
519 : : {
520 [ # # ]: 0 : pFndExp->nValue.PutDouble( pUFld->GetValue() );
521 : : }
522 : : }
523 : 6 : return pFndExp;
524 : : }
525 : :
526 : : // At this point the "real" case variable has to be used
527 [ + - ]: 18 : String sTmpName( rStr );
528 [ + - ]: 18 : ::ReplacePoint( sTmpName );
529 : :
530 [ + - ]: 18 : if( !ins )
531 : : {
532 : 18 : SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
533 : :
534 [ + - ]: 18 : String sDBName(GetDBName( sTmpName ));
535 [ + - ]: 18 : String sSourceName(sDBName.GetToken(0, DB_DELIM));
536 [ + - ][ + - ]: 18 : String sTableName(sDBName.GetToken(0).GetToken(1, DB_DELIM));
[ + - ]
537 [ + - ][ - + ]: 18 : if( pMgr && sSourceName.Len() && sTableName.Len() &&
[ # # ][ # # ]
[ - + ]
538 [ # # ]: 0 : pMgr->OpenDataSource(sSourceName, sTableName, -1, false))
539 : : {
540 [ # # ]: 0 : String sColumnName( GetColumnName( sTmpName ));
541 : : OSL_ENSURE(sColumnName.Len(), "Missing DB column name");
542 : :
543 [ # # ][ # # ]: 0 : String sDBNum( SwFieldType::GetTypeStr(TYP_DBSETNUMBERFLD) );
544 [ # # ][ # # ]: 0 : sDBNum = pCharClass->lowercase(sDBNum);
[ # # ]
545 : :
546 : : // Initialize again because this doesn't happen in docfld anymore for
547 : : // elements != RES_DBFLD. E.g. if there is an expression field before
548 : : // an DB_Field in a document.
549 [ # # ][ # # ]: 0 : VarChange( sDBNum, pMgr->GetSelectedRecordId(sSourceName, sTableName));
550 : :
551 [ # # ][ # # ]: 0 : if( sDBNum.EqualsIgnoreCaseAscii(sColumnName) )
552 : : {
553 [ # # ][ # # ]: 0 : aErrExpr.nValue.PutLong(long(pMgr->GetSelectedRecordId(sSourceName, sTableName)));
554 : 0 : return &aErrExpr;
555 : : }
556 : :
557 : 0 : sal_uLong nTmpRec = 0;
558 [ # # ][ # # ]: 0 : if( 0 != ( pFnd = Find( sDBNum, VarTable, TBLSZ ) ) )
559 [ # # ]: 0 : nTmpRec = ((SwCalcExp*)pFnd)->nValue.GetULong();
560 : :
561 : 0 : rtl::OUString sResult;
562 : 0 : double nNumber = DBL_MAX;
563 : :
564 [ # # ][ # # ]: 0 : long nLang = SvxLocaleToLanguage( pLclData->getLocale() );
565 [ # # ]: 0 : if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName,
566 [ # # ]: 0 : nTmpRec, nLang, sResult, &nNumber ))
567 : : {
568 [ # # ]: 0 : if (nNumber != DBL_MAX)
569 [ # # ]: 0 : aErrExpr.nValue.PutDouble( nNumber );
570 : : else
571 [ # # ]: 0 : aErrExpr.nValue.PutString( sResult );
572 : :
573 : 0 : return &aErrExpr;
574 [ # # ][ # # ]: 0 : }
[ # # ][ # # ]
[ # # ]
575 : : }
576 : : else
577 : : {
578 : : //data source was not available - set return to "NoValue"
579 : 18 : aErrExpr.nValue.SetVoidValue(true);
580 : : }
581 : : // NEVER save!
582 [ + - ][ + - ]: 18 : return &aErrExpr;
[ + - ]
583 : : }
584 : :
585 [ # # ][ # # ]: 0 : SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), 0 );
[ # # ][ # # ]
586 : 0 : pNewExp->pNext = VarTable[ ii ];
587 : 0 : VarTable[ ii ] = pNewExp;
588 : :
589 [ # # ]: 0 : String sColumnName( GetColumnName( sTmpName ));
590 : : OSL_ENSURE( sColumnName.Len(), "Missing DB column name" );
591 [ # # ]: 0 : if( sColumnName.EqualsIgnoreCaseAscii(
592 [ # # ][ # # ]: 0 : SwFieldType::GetTypeStr( TYP_DBSETNUMBERFLD ) ))
593 : : {
594 : 0 : SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
595 [ # # ]: 0 : String sDBName(GetDBName( sTmpName ));
596 [ # # ]: 0 : String sSourceName(sDBName.GetToken(0, DB_DELIM));
597 [ # # ][ # # ]: 0 : String sTableName(sDBName.GetToken(0).GetToken(1, DB_DELIM));
[ # # ]
598 [ # # ][ # # ]: 0 : if( pMgr && sSourceName.Len() && sTableName.Len() &&
[ # # ]
[ # # # # ]
[ # # ]
599 [ # # ]: 0 : pMgr->OpenDataSource(sSourceName, sTableName, -1, false) &&
600 : 0 : !pMgr->IsInMerge())
601 : : {
602 [ # # ][ # # ]: 0 : pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName));
603 : : }
604 : : else
605 : : {
606 : 0 : pNewExp->nValue.SetVoidValue(true);
607 [ # # ][ # # ]: 0 : }
[ # # ]
608 : : }
609 : :
610 [ # # ][ + - ]: 24 : return pNewExp;
[ + - ]
611 : : }
612 : :
613 : 0 : void SwCalc::VarChange( const String& rStr, double nValue )
614 : : {
615 [ # # ]: 0 : SwSbxValue aVal( nValue );
616 [ # # ][ # # ]: 0 : VarChange( rStr, aVal );
617 : 0 : }
618 : :
619 : 0 : void SwCalc::VarChange( const String& rStr, const SwSbxValue& rValue )
620 : : {
621 [ # # ][ # # ]: 0 : String aStr = pCharClass->lowercase( rStr );
[ # # ]
622 : :
623 : 0 : sal_uInt16 nPos = 0;
624 [ # # ]: 0 : SwCalcExp* pFnd = (SwCalcExp*)Find( aStr, VarTable, TBLSZ, &nPos );
625 : :
626 [ # # ]: 0 : if( !pFnd )
627 : : {
628 [ # # ][ # # ]: 0 : pFnd = new SwCalcExp( aStr, SwSbxValue( rValue ), 0 );
[ # # ][ # # ]
629 : 0 : pFnd->pNext = VarTable[ nPos ];
630 : 0 : VarTable[ nPos ] = pFnd;
631 : : }
632 : : else
633 : : {
634 [ # # ]: 0 : pFnd->nValue = rValue;
635 [ # # ]: 0 : }
636 : 0 : }
637 : :
638 : 0 : bool SwCalc::Push( const SwUserFieldType* pUserFieldType )
639 : : {
640 [ # # ][ # # ]: 0 : if( aRekurStk.end() != std::find(aRekurStk.begin(), aRekurStk.end(), pUserFieldType ) )
641 : 0 : return false;
642 : :
643 : 0 : aRekurStk.push_back( pUserFieldType );
644 : 0 : return true;
645 : : }
646 : :
647 : 0 : void SwCalc::Pop()
648 : : {
649 : : OSL_ENSURE( aRekurStk.size(), "SwCalc: Pop on an invalid pointer" );
650 : :
651 : 0 : aRekurStk.pop_back();
652 : 0 : }
653 : :
654 : 84 : SwCalcOper SwCalc::GetToken()
655 : : {
656 : : #if OSL_DEBUG_LEVEL > 1
657 : : // static for switch back to the "old" implementation of the calculator
658 : : // which doesn't use the I18N routines.
659 : : static int nUseOld = 0;
660 : : if( !nUseOld )
661 : : {
662 : : #endif
663 : :
664 [ + + ]: 84 : if( nCommandPos >= sCommand.Len() )
665 : 48 : return eCurrOper = CALC_ENDCALC;
666 : :
667 : : using namespace ::com::sun::star::i18n;
668 : : {
669 : : // Parse any token.
670 : : ParseResult aRes = pCharClass->parseAnyToken( sCommand, nCommandPos,
671 : : coStartFlags, aEmptyStr,
672 [ + - ]: 36 : coContFlags, aEmptyStr );
673 : :
674 : 36 : sal_Bool bSetError = sal_True;
675 : 36 : xub_StrLen nRealStt = nCommandPos + (xub_StrLen)aRes.LeadingWhiteSpace;
676 [ - + ]: 36 : if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
677 : : {
678 [ # # ]: 0 : nNumberValue.PutDouble( aRes.Value );
679 : 0 : eCurrOper = CALC_NUMBER;
680 : 0 : bSetError = sal_False;
681 : : }
682 [ + + ]: 36 : else if( aRes.TokenType & KParseType::IDENTNAME )
683 : : {
684 : : String aName( sCommand.Copy( nRealStt,
685 [ + - ]: 30 : static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
686 : : //#101436#: The variable may contain a database name. It must not be
687 : : // converted to lower case! Instead all further comparisons must be
688 : : // done case-insensitive
689 [ + - ][ + - ]: 30 : String sLowerCaseName = pCharClass->lowercase( aName );
[ + - ]
690 : : // catch currency symbol
691 [ - + ][ + - ]: 30 : if( sLowerCaseName == sCurrSym )
692 : : {
693 : 0 : nCommandPos = (xub_StrLen)aRes.EndPos;
694 [ # # ]: 0 : return GetToken(); // call again
695 : : }
696 : :
697 : : // catch operators
698 [ + - ]: 30 : _CalcOp* pFnd = ::FindOperator( sLowerCaseName );
699 [ + + ]: 30 : if( pFnd )
700 : : {
701 [ - - - - : 6 : switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
+ ]
702 : : {
703 : : case CALC_SUM:
704 : : case CALC_MEAN:
705 : 0 : eCurrListOper = CALC_PLUS;
706 : 0 : break;
707 : : case CALC_MIN:
708 : 0 : eCurrListOper = CALC_MIN_IN;
709 : 0 : break;
710 : : case CALC_MAX:
711 : 0 : eCurrListOper = CALC_MAX_IN;
712 : 0 : break;
713 : : case CALC_DATE:
714 : 0 : eCurrListOper = CALC_MONTH;
715 : 0 : break;
716 : : default:
717 : 6 : break;
718 : : }
719 : 6 : nCommandPos = (xub_StrLen)aRes.EndPos;
720 : 6 : return eCurrOper;
721 : : }
722 [ + - ]: 24 : aVarName = aName;
723 : 24 : eCurrOper = CALC_NAME;
724 [ + - ][ + + ]: 30 : bSetError = sal_False;
[ + - ][ + + ]
725 : : }
726 [ + - ]: 6 : else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
727 : : {
728 [ + - ][ + - ]: 6 : nNumberValue.PutString( String( aRes.DequotedNameOrString ));
[ + - ][ + - ]
729 : 6 : eCurrOper = CALC_NUMBER;
730 : 6 : bSetError = sal_False;
731 : : }
732 [ # # ]: 0 : else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
733 : : {
734 : : String aName( sCommand.Copy( nRealStt,
735 [ # # ]: 0 : static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
736 [ # # ]: 0 : if( 1 == aName.Len() )
737 : : {
738 : 0 : bSetError = sal_False;
739 : 0 : sal_Unicode ch = aName.GetChar( 0 );
740 [ # # # # : 0 : switch( ch )
# # # ]
741 : : {
742 : : case ';':
743 [ # # ][ # # ]: 0 : if( CALC_MONTH == eCurrListOper || CALC_DAY == eCurrListOper )
744 : : {
745 : 0 : eCurrOper = eCurrListOper;
746 : 0 : break;
747 : : }
748 : :
749 : : case '\n':
750 : 0 : eCurrOper = CALC_PRINT;
751 : 0 : break;
752 : :
753 : : case '%':
754 : : case '^':
755 : : case '*':
756 : : case '/':
757 : : case '+':
758 : : case '-':
759 : : case '(':
760 : : case ')':
761 : 0 : eCurrOper = SwCalcOper(ch);
762 : 0 : break;
763 : :
764 : : case '=':
765 : : case '!':
766 : : {
767 : : SwCalcOper eTmp2;
768 [ # # ]: 0 : if( '=' == ch )
769 : 0 : eCurrOper = SwCalcOper('='), eTmp2 = CALC_EQ;
770 : : else
771 : 0 : eCurrOper = CALC_NOT, eTmp2 = CALC_NEQ;
772 : :
773 [ # # # # ]: 0 : if( aRes.EndPos < sCommand.Len() &&
[ # # ]
774 : 0 : '=' == sCommand.GetChar( (xub_StrLen)aRes.EndPos ) )
775 : : {
776 : 0 : eCurrOper = eTmp2;
777 : 0 : ++aRes.EndPos;
778 : : }
779 : : }
780 : 0 : break;
781 : :
782 : : case cListDelim:
783 : 0 : eCurrOper = eCurrListOper;
784 : 0 : break;
785 : :
786 : : case '[':
787 [ # # ]: 0 : if( aRes.EndPos < sCommand.Len() )
788 : : {
789 [ # # ]: 0 : aVarName.Erase();
790 : 0 : xub_StrLen nFndPos = (xub_StrLen)aRes.EndPos,
791 : 0 : nSttPos = nFndPos;
792 : :
793 [ # # ]: 0 : do {
794 [ # # ][ # # ]: 0 : if( STRING_NOTFOUND != ( nFndPos =
795 : 0 : sCommand.Search( ']', nFndPos )) )
796 : : {
797 : : // ignore the ]
798 [ # # ]: 0 : if( '\\' == sCommand.GetChar(nFndPos-1))
799 : : {
800 : : aVarName += sCommand.Copy( nSttPos,
801 [ # # ][ # # ]: 0 : nFndPos - nSttPos - 1 );
[ # # ]
802 : 0 : nSttPos = ++nFndPos;
803 : : }
804 : : else
805 : 0 : break;
806 : : }
807 : : } while( STRING_NOTFOUND != nFndPos );
808 : :
809 [ # # ]: 0 : if( STRING_NOTFOUND != nFndPos )
810 : : {
811 [ # # ]: 0 : if( nSttPos != nFndPos )
812 : : aVarName += sCommand.Copy( nSttPos,
813 [ # # ][ # # ]: 0 : nFndPos - nSttPos );
[ # # ]
814 : 0 : aRes.EndPos = nFndPos + 1;
815 : 0 : eCurrOper = CALC_NAME;
816 : : }
817 : : else
818 : 0 : bSetError = sal_True;
819 : : }
820 : : else
821 : : {
822 : 0 : bSetError = sal_True;
823 : : }
824 : 0 : break;
825 : :
826 : : default:
827 : 0 : bSetError = sal_True;
828 : 0 : break;
829 : : }
830 [ # # ]: 0 : }
831 : : }
832 [ # # ]: 0 : else if( aRes.TokenType & KParseType::BOOLEAN )
833 : : {
834 : : String aName( sCommand.Copy( nRealStt,
835 [ # # ]: 0 : static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
836 [ # # ]: 0 : if( aName.Len() )
837 : : {
838 : 0 : sal_Unicode ch = aName.GetChar(0);
839 : :
840 : 0 : bSetError = sal_True;
841 [ # # ][ # # ]: 0 : if ('<' == ch || '>' == ch)
842 : : {
843 : 0 : bSetError = sal_False;
844 : :
845 [ # # ]: 0 : SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ;
846 [ # # ]: 0 : eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE;
847 : :
848 [ # # ][ # # ]: 0 : if( 2 == aName.Len() && '=' == aName.GetChar(1) )
[ # # ]
849 : 0 : eCurrOper = eTmp2;
850 [ # # ]: 0 : else if( 1 != aName.Len() )
851 : 0 : bSetError = sal_True;
852 : : }
853 [ # # ]: 0 : }
854 : : }
855 [ # # ]: 0 : else if( nRealStt == sCommand.Len() )
856 : : {
857 : 0 : eCurrOper = CALC_ENDCALC;
858 : 0 : bSetError = sal_False;
859 : : }
860 : :
861 [ - + ]: 30 : if( bSetError )
862 : : {
863 : 0 : eError = CALC_SYNTAX;
864 : 0 : eCurrOper = CALC_PRINT;
865 : : }
866 [ + + ]: 36 : nCommandPos = (xub_StrLen)aRes.EndPos;
867 : : };
868 : :
869 : : #if OSL_DEBUG_LEVEL > 1
870 : : #define NextCh( s, n ) (nCommandPos < sCommand.Len() ? sCommand.GetChar( nCommandPos++ ) : 0)
871 : :
872 : : }
873 : : else
874 : : {
875 : : sal_Unicode ch;
876 : : sal_Unicode cTSep = pLclData->getNumThousandSep()[0],
877 : : cDSep = pLclData->getNumDecimalSep()[0];
878 : :
879 : : do {
880 : : if( 0 == ( ch = NextCh( sCommand, nCommandPos ) ) )
881 : : return eCurrOper = CALC_ENDCALC;
882 : : } while ( ch == '\t' || ch == ' ' || ch == cTSep );
883 : :
884 : : if( ch == cDSep )
885 : : ch = '.';
886 : :
887 : : switch( ch )
888 : : {
889 : : case ';':
890 : : if( CALC_MONTH == eCurrListOper || CALC_DAY == eCurrListOper )
891 : : {
892 : : eCurrOper = eCurrListOper;
893 : : break;
894 : : } // else .. no break
895 : : case '\n':
896 : : {
897 : : sal_Unicode c;
898 : : while( nCommandPos < sCommand.Len() &&
899 : : ( ( c = sCommand.GetChar( nCommandPos ) ) == ' ' ||
900 : : c == '\t' || c == '\x0a' || c == '\x0d' ))
901 : : {
902 : : ++nCommandPos;
903 : : }
904 : : eCurrOper = CALC_PRINT;
905 : : }
906 : : break;
907 : :
908 : : case '%':
909 : : case '^':
910 : : case '*':
911 : : case '/':
912 : : case '+':
913 : : case '-':
914 : : case '(':
915 : : case ')':
916 : : eCurrOper = SwCalcOper(ch);
917 : : break;
918 : :
919 : : case '=':
920 : : if( '=' == sCommand.GetChar( nCommandPos ) )
921 : : {
922 : : ++nCommandPos;
923 : : eCurrOper = CALC_EQ;
924 : : }
925 : : else
926 : : {
927 : : eCurrOper = SwCalcOper(ch);
928 : : }
929 : : break;
930 : :
931 : : case '!':
932 : : if( '=' == sCommand.GetChar( nCommandPos ) )
933 : : {
934 : : ++nCommandPos;
935 : : eCurrOper = CALC_NEQ;
936 : : }
937 : : else
938 : : {
939 : : eCurrOper = CALC_NOT;
940 : : }
941 : : break;
942 : :
943 : : case '>':
944 : : case '<':
945 : : eCurrOper = '>' == ch ? CALC_GRE : CALC_LES;
946 : : if( '=' == (ch = sCommand.GetChar( nCommandPos ) ) )
947 : : {
948 : : ++nCommandPos;
949 : : eCurrOper = CALC_GRE == eCurrOper ? CALC_GEQ : CALC_LEQ;
950 : : }
951 : : else if( ' ' != ch )
952 : : {
953 : : eError = CALC_SYNTAX;
954 : : eCurrOper = CALC_PRINT;
955 : : }
956 : : break;
957 : :
958 : : case cListDelim :
959 : : eCurrOper = eCurrListOper;
960 : : break;
961 : :
962 : : case '0': case '1': case '2': case '3': case '4':
963 : : case '5': case '6': case '7': case '8': case '9':
964 : : case ',':
965 : : case '.':
966 : : {
967 : : double nVal;
968 : : --nCommandPos; // back to the first char
969 : : if( Str2Double( sCommand, nCommandPos, nVal, pLclData ))
970 : : {
971 : : nNumberValue.PutDouble( nVal );
972 : : eCurrOper = CALC_NUMBER;
973 : : }
974 : : else
975 : : {
976 : : // erroneous number
977 : : eError = CALC_SYNTAX;
978 : : eCurrOper = CALC_PRINT;
979 : : }
980 : : }
981 : : break;
982 : :
983 : : case '[':
984 : : {
985 : : String aStr;
986 : : sal_Bool bIgnore = sal_False;
987 : : do {
988 : : while( 0 != ( ch = NextCh( sCommand, nCommandPos )) &&
989 : : ch != ']' )
990 : : {
991 : : if( !bIgnore && '\\' == ch )
992 : : bIgnore = sal_True;
993 : : else if( bIgnore )
994 : : bIgnore = sal_False;
995 : : aStr += ch;
996 : : }
997 : :
998 : : if( !bIgnore )
999 : : break;
1000 : :
1001 : : aStr.SetChar( aStr.Len() - 1, ch );
1002 : : } while( ch );
1003 : :
1004 : : aVarName = aStr;
1005 : : eCurrOper = CALC_NAME;
1006 : : }
1007 : : break;
1008 : :
1009 : : case '"':
1010 : : {
1011 : : xub_StrLen nStt = nCommandPos;
1012 : : while( 0 != ( ch = NextCh( sCommand, nCommandPos ) ) &&
1013 : : '"' != ch )
1014 : : {
1015 : : ;
1016 : : }
1017 : :
1018 : : xub_StrLen nLen = nCommandPos - nStt;
1019 : : if( '"' == ch )
1020 : : --nLen;
1021 : : nNumberValue.PutString( sCommand.Copy( nStt, nLen ));
1022 : : eCurrOper = CALC_NUMBER;
1023 : : }
1024 : : break;
1025 : :
1026 : : default:
1027 : : if (ch && (pCharClass->isLetter( sCommand, nCommandPos - 1) ||
1028 : : '_' == ch))
1029 : : {
1030 : : xub_StrLen nStt = nCommandPos-1;
1031 : : while( 0 != (ch = NextCh( sCommand, nCommandPos )) &&
1032 : : (pCharClass->isLetterNumeric( sCommand, nCommandPos - 1) ||
1033 : : ch == '_' || ch == '.' ) )
1034 : : {
1035 : : ;
1036 : : }
1037 : :
1038 : : if( ch )
1039 : : --nCommandPos;
1040 : :
1041 : : String aStr( sCommand.Copy( nStt, nCommandPos-nStt ));
1042 : : aStr = pCharClass->lowercase( aStr );
1043 : :
1044 : : // catch currency symbol
1045 : : if( aStr == sCurrSym )
1046 : : return GetToken(); // call again
1047 : :
1048 : : // catch operators
1049 : : _CalcOp* pFnd = ::FindOperator( aStr );
1050 : : if( pFnd )
1051 : : {
1052 : : switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
1053 : : {
1054 : : case CALC_SUM :
1055 : : case CALC_MEAN :
1056 : : eCurrListOper = CALC_PLUS;
1057 : : break;
1058 : : case CALC_MIN :
1059 : : eCurrListOper = CALC_MIN_IN;
1060 : : break;
1061 : : case CALC_MAX :
1062 : : eCurrListOper = CALC_MAX_IN;
1063 : : break;
1064 : : case CALC_DATE :
1065 : : eCurrListOper = CALC_MONTH;
1066 : : break;
1067 : : default :
1068 : : break;
1069 : : }
1070 : : return eCurrOper;
1071 : : }
1072 : : aVarName = aStr;
1073 : : eCurrOper = CALC_NAME;
1074 : : }
1075 : : else
1076 : : {
1077 : : eError = CALC_SYNTAX;
1078 : : eCurrOper = CALC_PRINT;
1079 : : }
1080 : : break;
1081 : : }
1082 : : }
1083 : : #endif
1084 : 84 : return eCurrOper;
1085 : : }
1086 : :
1087 : 24 : SwSbxValue SwCalc::Term()
1088 : : {
1089 : 24 : SwSbxValue left( Prim() );
1090 [ + - ]: 24 : nLastLeft = left;
1091 : 30 : for(;;)
1092 : : {
1093 : 30 : sal_uInt16 nSbxOper = USHRT_MAX;
1094 : :
1095 [ - - - - : 30 : switch( eCurrOper )
+ - - - -
- - - - -
- - + ]
1096 : : {
1097 : : case CALC_AND:
1098 : : {
1099 [ # # ]: 0 : GetToken();
1100 [ # # ][ # # ]: 0 : sal_Bool bB = Prim().GetBool();
[ # # ]
1101 [ # # ][ # # ]: 0 : left.PutBool( left.GetBool() && bB );
[ # # ][ # # ]
1102 : : }
1103 : 0 : break;
1104 : : case CALC_OR:
1105 : : {
1106 [ # # ]: 0 : GetToken();
1107 [ # # ][ # # ]: 0 : sal_Bool bB = Prim().GetBool();
[ # # ]
1108 [ # # ][ # # ]: 0 : left.PutBool( left.GetBool() || bB );
[ # # ][ # # ]
1109 : : }
1110 : 0 : break;
1111 : : case CALC_XOR:
1112 : : {
1113 [ # # ]: 0 : GetToken();
1114 [ # # ][ # # ]: 0 : sal_Bool bR = Prim().GetBool();
[ # # ]
1115 [ # # ]: 0 : sal_Bool bL = left.GetBool();
1116 [ # # ][ # # ]: 0 : left.PutBool( (bL && !bR) || (!bL && bR) );
[ # # ][ # # ]
[ # # ]
1117 : : }
1118 : 0 : break;
1119 : :
1120 : 0 : case CALC_EQ: nSbxOper = SbxEQ; break;
1121 : 6 : case CALC_NEQ: nSbxOper = SbxNE; break;
1122 : 0 : case CALC_LEQ: nSbxOper = SbxLE; break;
1123 : 0 : case CALC_GEQ: nSbxOper = SbxGE; break;
1124 : 0 : case CALC_GRE: nSbxOper = SbxGT; break;
1125 : 0 : case CALC_LES: nSbxOper = SbxLT; break;
1126 : :
1127 : 0 : case CALC_MUL: nSbxOper = SbxMUL; break;
1128 : 0 : case CALC_DIV: nSbxOper = SbxDIV; break;
1129 : :
1130 : : case CALC_MIN_IN:
1131 : : {
1132 [ # # ]: 0 : GetToken();
1133 [ # # ]: 0 : SwSbxValue e = Prim();
1134 [ # # ][ # # ]: 0 : left = left.GetDouble() < e.GetDouble() ? left : e;
[ # # ][ # # ]
[ # # ]
1135 : : }
1136 : 0 : break;
1137 : : case CALC_MAX_IN:
1138 : : {
1139 [ # # ]: 0 : GetToken();
1140 [ # # ]: 0 : SwSbxValue e = Prim();
1141 [ # # ][ # # ]: 0 : left = left.GetDouble() > e.GetDouble() ? left : e;
[ # # ][ # # ]
[ # # ]
1142 : : }
1143 : 0 : break;
1144 : : case CALC_MONTH:
1145 : : {
1146 [ # # ]: 0 : GetToken();
1147 [ # # ]: 0 : SwSbxValue e = Prim();
1148 [ # # ]: 0 : sal_Int32 nYear = (sal_Int32) floor( left.GetDouble() );
1149 : 0 : nYear = nYear & 0x0000FFFF;
1150 [ # # ]: 0 : sal_Int32 nMonth = (sal_Int32) floor( e.GetDouble() );
1151 : 0 : nMonth = ( nMonth & 0x000000FF ) << 16;
1152 [ # # ]: 0 : left.PutLong( nMonth + nYear );
1153 [ # # ]: 0 : eCurrOper = CALC_DAY;
1154 : : }
1155 : 0 : break;
1156 : : case CALC_DAY:
1157 : : {
1158 [ # # ]: 0 : GetToken();
1159 [ # # ]: 0 : SwSbxValue e = Prim();
1160 [ # # ]: 0 : sal_Int32 nYearMonth = (sal_Int32) floor( left.GetDouble() );
1161 : 0 : nYearMonth = nYearMonth & 0x00FFFFFF;
1162 [ # # ]: 0 : sal_Int32 nDay = (sal_Int32) floor( e.GetDouble() );
1163 : 0 : nDay = ( nDay & 0x000000FF ) << 24;
1164 [ # # ][ # # ]: 0 : left = lcl_ConvertToDateValue( rDoc, nDay + nYearMonth );
[ # # ][ # # ]
[ # # ]
1165 : : }
1166 : 0 : break;
1167 : : case CALC_ROUND:
1168 : : {
1169 [ # # ]: 0 : GetToken();
1170 [ # # ]: 0 : SwSbxValue e = Prim();
1171 : :
1172 : 0 : double fVal = 0;
1173 : 0 : double fFac = 1;
1174 [ # # ]: 0 : sal_Int32 nDec = (sal_Int32) floor( e.GetDouble() );
1175 [ # # ][ # # ]: 0 : if( nDec < -20 || nDec > 20 )
1176 : : {
1177 : 0 : eError = CALC_OVERFLOW;
1178 [ # # ]: 0 : left.Clear();
1179 : : return left;
1180 : : }
1181 [ # # ]: 0 : fVal = left.GetDouble();
1182 : : sal_uInt16 i;
1183 [ # # ]: 0 : if( nDec >= 0)
1184 : : {
1185 [ # # ]: 0 : for (i = 0; i < (sal_uInt16) nDec; ++i )
1186 : 0 : fFac *= 10.0;
1187 : : }
1188 : : else
1189 : : {
1190 [ # # ]: 0 : for (i = 0; i < (sal_uInt16) -nDec; ++i )
1191 : 0 : fFac /= 10.0;
1192 : : }
1193 : :
1194 : 0 : fVal *= fFac;
1195 : : sal_Bool bSign;
1196 [ # # ]: 0 : if (fVal < 0.0)
1197 : : {
1198 : 0 : fVal *= -1.0;
1199 : 0 : bSign = sal_True;
1200 : : }
1201 : : else
1202 : : {
1203 : 0 : bSign = sal_False;
1204 : : }
1205 : :
1206 : : // rounding
1207 : 0 : double fNum = fVal; // find the exponent
1208 : 0 : int nExp = 0;
1209 [ # # ]: 0 : if( fNum > 0 )
1210 : : {
1211 [ # # ]: 0 : while( fNum < 1.0 )
1212 : 0 : fNum *= 10.0, --nExp;
1213 [ # # ]: 0 : while( fNum >= 10.0 )
1214 : 0 : fNum /= 10.0, ++nExp;
1215 : : }
1216 : 0 : nExp = 15 - nExp;
1217 [ # # ]: 0 : if( nExp > 15 )
1218 : 0 : nExp = 15;
1219 [ # # ]: 0 : else if( nExp <= 1 )
1220 : 0 : nExp = 0;
1221 : 0 : fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
1222 : :
1223 [ # # ]: 0 : if (bSign)
1224 : 0 : fVal *= -1.0;
1225 : :
1226 : 0 : fVal /= fFac;
1227 : :
1228 [ # # ][ # # ]: 0 : left.PutDouble( fVal );
[ # # ]
1229 : : }
1230 : 0 : break;
1231 : :
1232 : : //#77448# (=2*3^2 != 18)
1233 : :
1234 : : default:
1235 : 24 : return left;
1236 : : }
1237 : :
1238 [ + - ]: 6 : if( USHRT_MAX != nSbxOper )
1239 : : {
1240 : : // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
1241 : 6 : SbxOperator eSbxOper = (SbxOperator)nSbxOper;
1242 : :
1243 [ + - ]: 6 : GetToken();
1244 [ + - ][ + - ]: 6 : if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
1245 : : {
1246 [ + - ][ + - ]: 6 : left.PutBool( left.Compare( eSbxOper, Prim() ));
[ + - ][ + - ]
1247 : : }
1248 : : else
1249 : : {
1250 [ # # ]: 0 : SwSbxValue aRight( Prim() );
1251 [ # # ]: 0 : aRight.MakeDouble();
1252 [ # # ]: 0 : left.MakeDouble();
1253 : :
1254 [ # # ][ # # ]: 0 : if( SbxDIV == eSbxOper && !aRight.GetDouble() )
[ # # ][ # # ]
1255 : 0 : eError = CALC_ZERODIV;
1256 : : else
1257 [ # # ][ # # ]: 6 : left.Compute( eSbxOper, aRight );
1258 : : }
1259 : : }
1260 : 0 : }
1261 : : }
1262 : :
1263 : : extern "C" typedef double (*pfCalc)( double );
1264 : :
1265 : 30 : SwSbxValue SwCalc::Prim()
1266 : : {
1267 : 30 : SwSbxValue nErg;
1268 : :
1269 : 30 : pfCalc pFnc = 0;
1270 : :
1271 : 30 : sal_Bool bChkTrig = sal_False, bChkPow = sal_False;
1272 : :
1273 [ - - - - : 30 : switch( eCurrOper )
- - - + +
- - - - -
- - ]
1274 : : {
1275 : 0 : case CALC_SIN: pFnc = &sin; break;
1276 : 0 : case CALC_COS: pFnc = &cos; break;
1277 : 0 : case CALC_TAN: pFnc = &tan; break;
1278 : 0 : case CALC_ATAN: pFnc = &atan; break;
1279 : 0 : case CALC_ASIN: pFnc = &asin; bChkTrig = sal_True; break;
1280 : 0 : case CALC_ACOS: pFnc = &acos; bChkTrig = sal_True; break;
1281 : :
1282 : : case CALC_NOT:
1283 : : {
1284 [ # # ]: 0 : GetToken();
1285 [ # # ][ # # ]: 0 : nErg = Prim();
[ # # ]
1286 [ # # ][ # # ]: 0 : if( SbxSTRING == nErg.GetType() )
1287 : : {
1288 [ # # ][ # # ]: 0 : nErg.PutBool( 0 == nErg.GetString().Len() );
1289 : : }
1290 [ # # ][ # # ]: 0 : else if(SbxBOOL == nErg.GetType() )
1291 : : {
1292 [ # # ][ # # ]: 0 : nErg.PutBool(!nErg.GetBool());
1293 : : }
1294 : : // Evaluate arguments manually so that the binary NOT below does not
1295 : : // get called. We want a BOOLEAN NOT.
1296 [ # # ][ # # ]: 0 : else if (nErg.IsNumeric())
1297 : : {
1298 [ # # ][ # # ]: 0 : nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
[ # # ]
1299 : : }
1300 : : else
1301 : : {
1302 : : OSL_FAIL( "unexpected case. computing binary NOT" );
1303 : : //!! computes a binary NOT
1304 [ # # ]: 0 : nErg.Compute( SbxNOT, nErg );
1305 : : }
1306 : : }
1307 : 0 : break;
1308 : :
1309 : : case CALC_NUMBER:
1310 [ + - ][ - + ]: 6 : if( GetToken() == CALC_PHD )
1311 : : {
1312 [ # # ]: 0 : double aTmp = nNumberValue.GetDouble();
1313 : 0 : aTmp *= 0.01;
1314 [ # # ]: 0 : nErg.PutDouble( aTmp );
1315 [ # # ]: 0 : GetToken();
1316 : : }
1317 [ - + ]: 6 : else if( eCurrOper == CALC_NAME )
1318 : : {
1319 : 0 : eError = CALC_SYNTAX;
1320 : : }
1321 : : else
1322 : : {
1323 [ + - ]: 6 : nErg = nNumberValue;
1324 : 6 : bChkPow = sal_True;
1325 : : }
1326 : 6 : break;
1327 : :
1328 : : case CALC_NAME:
1329 [ + - ][ - + ]: 24 : if( GetToken() == CALC_ASSIGN )
1330 : : {
1331 [ # # ]: 0 : SwCalcExp* n = VarInsert( aVarName );
1332 [ # # ]: 0 : GetToken();
1333 [ # # ][ # # ]: 0 : nErg = n->nValue = Expr();
[ # # ][ # # ]
1334 : : }
1335 : : else
1336 : : {
1337 [ + - ][ + - ]: 24 : nErg = VarLook( aVarName )->nValue;
1338 : 24 : bChkPow = sal_True;
1339 : : }
1340 : 24 : break;
1341 : :
1342 : : case CALC_MINUS:
1343 [ # # ]: 0 : GetToken();
1344 [ # # ][ # # ]: 0 : nErg.PutDouble( -(Prim().GetDouble()) );
[ # # ][ # # ]
1345 : 0 : break;
1346 : :
1347 : : case CALC_LP:
1348 : : {
1349 [ # # ]: 0 : GetToken();
1350 [ # # ][ # # ]: 0 : nErg = Expr();
[ # # ]
1351 [ # # ]: 0 : if( eCurrOper != CALC_RP )
1352 : : {
1353 : 0 : eError = CALC_BRACK;
1354 : : }
1355 : : else
1356 : : {
1357 [ # # ]: 0 : GetToken();
1358 : 0 : bChkPow = sal_True; // in order for =(7)^2 to work
1359 : : }
1360 : : }
1361 : 0 : break;
1362 : :
1363 : : case CALC_MEAN:
1364 : : {
1365 : 0 : nListPor = 1;
1366 [ # # ]: 0 : GetToken();
1367 [ # # ][ # # ]: 0 : nErg = Expr();
[ # # ]
1368 [ # # ]: 0 : double aTmp = nErg.GetDouble();
1369 : 0 : aTmp /= nListPor;
1370 [ # # ]: 0 : nErg.PutDouble( aTmp );
1371 : : }
1372 : 0 : break;
1373 : :
1374 : : case CALC_SQRT:
1375 : : {
1376 [ # # ]: 0 : GetToken();
1377 [ # # ][ # # ]: 0 : nErg = Prim();
[ # # ]
1378 [ # # ][ # # ]: 0 : if( nErg.GetDouble() < 0 )
1379 : 0 : eError = CALC_OVERFLOW;
1380 : : else
1381 [ # # ][ # # ]: 0 : nErg.PutDouble( sqrt( nErg.GetDouble() ));
1382 : : }
1383 : 0 : break;
1384 : :
1385 : : case CALC_SUM:
1386 : : case CALC_DATE:
1387 : : case CALC_MIN:
1388 : : case CALC_MAX:
1389 [ # # ]: 0 : GetToken();
1390 [ # # ][ # # ]: 0 : nErg = Expr();
[ # # ]
1391 : 0 : break;
1392 : :
1393 : : case CALC_ENDCALC:
1394 [ # # ]: 0 : nErg.Clear();
1395 : 0 : break;
1396 : :
1397 : : default:
1398 : 0 : eError = CALC_SYNTAX;
1399 : 0 : break;
1400 : : }
1401 : :
1402 [ - + ]: 30 : if( pFnc )
1403 : : {
1404 [ # # ]: 0 : GetToken();
1405 [ # # ][ # # ]: 0 : double nVal = Prim().GetDouble();
[ # # ]
1406 [ # # ][ # # ]: 0 : if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
[ # # ]
1407 [ # # ][ # # ]: 0 : nErg.PutDouble( (*pFnc)( nVal ) );
1408 : : else
1409 : 0 : eError = CALC_OVERFLOW;
1410 : : }
1411 : :
1412 [ + - ][ - + ]: 30 : if( bChkPow && eCurrOper == CALC_POW )
1413 : : {
1414 [ # # ]: 0 : double dleft = nErg.GetDouble();
1415 [ # # ]: 0 : GetToken();
1416 [ # # ][ # # ]: 0 : double right = Prim().GetDouble();
[ # # ]
1417 : :
1418 : : double fraction, integer;
1419 : 0 : fraction = modf( right, &integer );
1420 [ # # ][ # # ]: 0 : if( ( dleft < 0.0 && 0.0 != fraction ) ||
[ # # ][ # # ]
1421 : : ( 0.0 == dleft && right < 0.0 ) )
1422 : : {
1423 : 0 : eError = CALC_OVERFLOW;
1424 [ # # ]: 0 : nErg.Clear();
1425 : : }
1426 : : else
1427 : : {
1428 : 0 : dleft = pow(dleft, right );
1429 [ # # ]: 0 : if( dleft == HUGE_VAL )
1430 : : {
1431 : 0 : eError = CALC_POWERR;
1432 [ # # ]: 0 : nErg.Clear();
1433 : : }
1434 : : else
1435 : : {
1436 [ # # ]: 0 : nErg.PutDouble( dleft );
1437 : : }
1438 : : }
1439 : : }
1440 : :
1441 : 30 : return nErg;
1442 : : }
1443 : :
1444 : 24 : SwSbxValue SwCalc::Expr()
1445 : : {
1446 [ + - ][ + - ]: 24 : SwSbxValue left = Term(), right;
1447 [ + - ]: 24 : nLastLeft = left;
1448 : 0 : for(;;)
1449 : : {
1450 [ - - + ]: 24 : switch(eCurrOper)
1451 : : {
1452 : : case CALC_PLUS:
1453 [ # # ]: 0 : GetToken();
1454 [ # # ]: 0 : left.MakeDouble();
1455 [ # # ][ # # ]: 0 : ( right = Term() ).MakeDouble();
[ # # ][ # # ]
1456 [ # # ]: 0 : left.Compute( SbxPLUS, right );
1457 : 0 : nListPor++;
1458 : 0 : break;
1459 : :
1460 : : case CALC_MINUS:
1461 [ # # ]: 0 : GetToken();
1462 [ # # ]: 0 : left.MakeDouble();
1463 [ # # ][ # # ]: 0 : ( right = Term() ).MakeDouble();
[ # # ][ # # ]
1464 [ # # ]: 0 : left.Compute( SbxMINUS, right );
1465 : 0 : break;
1466 : :
1467 : : default:
1468 : 24 : return left;
1469 : : }
1470 [ + - ]: 24 : }
1471 : : }
1472 : :
1473 : 0 : String SwCalc::GetColumnName(const String& rName)
1474 : : {
1475 : 0 : xub_StrLen nPos = rName.Search(DB_DELIM);
1476 [ # # ]: 0 : if( STRING_NOTFOUND != nPos )
1477 : : {
1478 : 0 : nPos = rName.Search(DB_DELIM, nPos + 1);
1479 : :
1480 [ # # ]: 0 : if( STRING_NOTFOUND != nPos )
1481 : 0 : return rName.Copy(nPos + 1);
1482 : : }
1483 : 0 : return rName;
1484 : : }
1485 : :
1486 : 18 : String SwCalc::GetDBName(const String& rName)
1487 : : {
1488 [ + - ]: 18 : xub_StrLen nPos = rName.Search(DB_DELIM);
1489 [ - + ]: 18 : if( STRING_NOTFOUND != nPos )
1490 : : {
1491 [ # # ]: 0 : nPos = rName.Search(DB_DELIM, nPos + 1);
1492 : :
1493 [ # # ]: 0 : if( STRING_NOTFOUND != nPos )
1494 [ # # ]: 0 : return rName.Copy( 0, nPos );
1495 : : }
1496 [ + - ]: 18 : SwDBData aData = rDoc.GetDBData();
1497 [ + - ]: 18 : String sRet = aData.sDataSource;
1498 [ + - ]: 18 : sRet += DB_DELIM;
1499 [ + - ][ + - ]: 18 : sRet += String(aData.sCommand);
[ + - ]
1500 [ + - ][ + - ]: 18 : return sRet;
1501 : : }
1502 : :
1503 : : namespace
1504 : : {
1505 : 0 : static bool lcl_Str2Double( const String& rCommand, xub_StrLen& rCommandPos,
1506 : : double& rVal,
1507 : : const LocaleDataWrapper* const pLclData )
1508 : : {
1509 : : OSL_ASSERT(pLclData);
1510 : 0 : const xub_Unicode nCurrCmdPos = rCommandPos;
1511 : : rtl_math_ConversionStatus eStatus;
1512 : : const sal_Unicode* pEnd;
1513 : 0 : rVal = rtl_math_uStringToDouble( rCommand.GetBuffer() + rCommandPos,
1514 : 0 : rCommand.GetBuffer() + rCommand.Len(),
1515 [ # # ]: 0 : pLclData->getNumDecimalSep()[0],
1516 [ # # ]: 0 : pLclData->getNumThousandSep()[0],
1517 : : &eStatus,
1518 : 0 : &pEnd );
1519 : 0 : rCommandPos = static_cast<xub_StrLen>(pEnd - rCommand.GetBuffer());
1520 : :
1521 : : return rtl_math_ConversionStatus_Ok == eStatus &&
1522 [ # # ][ # # ]: 0 : nCurrCmdPos != rCommandPos;
1523 : : }
1524 : : }
1525 : :
1526 : 0 : bool SwCalc::Str2Double( const String& rCommand, xub_StrLen& rCommandPos,
1527 : : double& rVal, const LocaleDataWrapper* const pLclData )
1528 : : {
1529 [ # # ]: 0 : const SvtSysLocale aSysLocale;
1530 : : return lcl_Str2Double( rCommand, rCommandPos, rVal,
1531 [ # # ][ # # ]: 0 : pLclData ? pLclData : aSysLocale.GetLocaleDataPtr() );
[ # # ][ # # ]
1532 : : }
1533 : :
1534 : 0 : bool SwCalc::Str2Double( const String& rCommand, xub_StrLen& rCommandPos,
1535 : : double& rVal, SwDoc* const pDoc )
1536 : : {
1537 [ # # ]: 0 : const SvtSysLocale aSysLocale;
1538 : 0 : ::std::auto_ptr<const LocaleDataWrapper> pLclD;
1539 [ # # ]: 0 : if( pDoc )
1540 : : {
1541 [ # # ]: 0 : LanguageType eLang = GetDocAppScriptLang( *pDoc );
1542 [ # # ]: 0 : if (eLang !=
1543 [ # # ][ # # ]: 0 : SvxLocaleToLanguage(aSysLocale.GetLocaleData().getLocale()))
[ # # ]
1544 : : {
1545 : : pLclD.reset( new LocaleDataWrapper(
1546 : : ::comphelper::getProcessServiceFactory(),
1547 [ # # ][ # # ]: 0 : SvxCreateLocale( eLang ) ) );
[ # # ][ # # ]
1548 : : }
1549 : : }
1550 : :
1551 : : bool const bRet = lcl_Str2Double( rCommand, rCommandPos, rVal,
1552 [ # # ][ # # ]: 0 : (pLclD.get()) ? pLclD.get() : aSysLocale.GetLocaleDataPtr() );
[ # # ]
1553 : :
1554 [ # # ][ # # ]: 0 : return bRet;
1555 : : }
1556 : :
1557 : 0 : sal_Bool SwCalc::IsValidVarName( const String& rStr, String* pValidName )
1558 : : {
1559 : 0 : sal_Bool bRet = sal_False;
1560 : : using namespace ::com::sun::star::i18n;
1561 : : {
1562 : : // Parse any token.
1563 [ # # ]: 0 : ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1564 : : coStartFlags, aEmptyStr,
1565 [ # # ]: 0 : coContFlags, aEmptyStr );
1566 : :
1567 [ # # ]: 0 : if( aRes.TokenType & KParseType::IDENTNAME )
1568 : : {
1569 : 0 : bRet = aRes.EndPos == rStr.Len();
1570 [ # # ]: 0 : if( pValidName )
1571 : : {
1572 : 0 : xub_StrLen nRealStt = (xub_StrLen)aRes.LeadingWhiteSpace;
1573 : : *pValidName = rStr.Copy( nRealStt,
1574 [ # # ][ # # ]: 0 : static_cast<xub_StrLen>(aRes.EndPos) - nRealStt );
[ # # ]
1575 : : }
1576 : : }
1577 [ # # ]: 0 : else if( pValidName )
1578 [ # # ]: 0 : pValidName->Erase();
1579 : : }
1580 : 0 : return bRet;
1581 : : }
1582 : :
1583 : 714 : SwHash::SwHash( const String& rStr ) :
1584 : : aStr( rStr ),
1585 : 714 : pNext( 0 )
1586 : : {
1587 : 714 : }
1588 : :
1589 : 693 : SwHash::~SwHash()
1590 : : {
1591 [ + + ][ + - ]: 693 : delete pNext;
1592 [ - + ]: 693 : }
1593 : :
1594 : 9 : void DeleteHashTable( SwHash **ppHashTable, sal_uInt16 nCount )
1595 : : {
1596 [ + + ]: 324 : for ( sal_uInt16 i = 0; i < nCount; ++i )
1597 [ + + ]: 315 : delete *(ppHashTable+i);
1598 [ + - ]: 9 : delete [] ppHashTable;
1599 : 9 : }
1600 : :
1601 : 654 : SwCalcExp::SwCalcExp( const String& rStr, const SwSbxValue& rVal,
1602 : : const SwFieldType* pType )
1603 : : : SwHash( rStr ),
1604 : : nValue( rVal ),
1605 [ + - ]: 654 : pFldType( pType )
1606 : : {
1607 : 654 : }
1608 : :
1609 [ + - ][ # # ]: 1668 : SwSbxValue::~SwSbxValue()
1610 : : {
1611 [ + - ][ - + ]: 1668 : }
[ # # ][ # # ]
[ # # ][ # # ]
1612 : :
1613 : 18 : sal_Bool SwSbxValue::GetBool() const
1614 : : {
1615 : 18 : return SbxSTRING == GetType() ? 0 != GetString().Len()
1616 [ - + ]: 18 : : 0 != SbxValue::GetBool();
1617 : : }
1618 : :
1619 : 0 : double SwSbxValue::GetDouble() const
1620 : : {
1621 : : double nRet;
1622 [ # # ][ # # ]: 0 : if( SbxSTRING == GetType() )
1623 : : {
1624 : 0 : xub_StrLen nStt = 0;
1625 [ # # ][ # # ]: 0 : SwCalc::Str2Double( GetString(), nStt, nRet );
1626 : : }
1627 [ # # ][ # # ]: 0 : else if (IsBool())
1628 : : {
1629 [ # # ][ # # ]: 0 : nRet = 0 != GetBool() ? 1.0 : 0.0;
1630 : : }
1631 : : else
1632 : : {
1633 [ # # ]: 0 : nRet = SbxValue::GetDouble();
1634 : : }
1635 : 0 : return nRet;
1636 : : }
1637 : :
1638 : 0 : SwSbxValue& SwSbxValue::MakeDouble()
1639 : : {
1640 [ # # ][ # # ]: 0 : if( GetType() == SbxSTRING || GetType() == SbxBOOL )
[ # # ]
1641 : 0 : PutDouble( GetDouble() );
1642 : 0 : return *this;
1643 : : }
1644 : :
1645 : : #ifdef STANDALONE_HASHCALC
1646 : :
1647 : : // this is example code how to create hash values in the CTOR:
1648 : :
1649 : : #include <stdio.h>
1650 : : void main()
1651 : : {
1652 : : static sal_Char
1653 : : sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
1654 : : sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
1655 : : sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
1656 : : sNType9[] = "word", sNType10[]= "char",
1657 : : sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
1658 : : sNType13[] = "user_lastname" , sNType14[] = "user_initials",
1659 : : sNType15[] = "user_street" , sNType16[] = "user_country" ,
1660 : : sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
1661 : : sNType19[] = "user_title" , sNType20[] = "user_position" ,
1662 : : sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
1663 : : sNType23[] = "user_fax" , sNType24[] = "user_email" ,
1664 : : sNType25[] = "user_state", sNType26[] = "graph"
1665 : : ;
1666 : :
1667 : : static const sal_Char* sNTypeTab[ 27 ] =
1668 : : {
1669 : : sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1670 : : sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1671 : : sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1672 : : sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1673 : : sNType24, sNType25, sNType26
1674 : : };
1675 : :
1676 : : const unsigned short nTblSize = 47;
1677 : : int aArr[ nTblSize ] = { 0 };
1678 : : sal_Char ch;
1679 : :
1680 : : for( int n = 0; n < 27; ++n )
1681 : : {
1682 : : unsigned long ii = 0;
1683 : : const sal_Char* pp = sNTypeTab[ n ];
1684 : :
1685 : : while( *pp )
1686 : : {
1687 : : ii = ii << 1 ^ *pp++;
1688 : : }
1689 : : ii %= nTblSize;
1690 : :
1691 : : ch = aArr[ ii ] ? 'X' : ' ';
1692 : : aArr[ ii ] = 1;
1693 : : printf( "%-20s -> %3d [%c]\n", sNTypeTab[ n ], ii, ch );
1694 : : }
1695 : : }
1696 : :
1697 : : #endif
1698 : :
1699 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|