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