LibreOffice Module sc (master)  1
global2.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sfx2/docfile.hxx>
21 #include <sfx2/objsh.hxx>
22 #include <unotools/configmgr.hxx>
23 #include <unotools/pathoptions.hxx>
24 #include <tools/urlobj.hxx>
25 #include <svl/zforlist.hxx>
26 #include <formula/errorcodes.hxx>
27 #include <sal/log.hxx>
28 #include <rtl/character.hxx>
29 
30 #include <global.hxx>
31 #include <rangeutl.hxx>
32 #include <compiler.hxx>
33 #include <paramisc.hxx>
34 #include <calcconfig.hxx>
35 
36 // struct ScImportParam:
37 
39  nCol1(0),
40  nRow1(0),
41  nCol2(0),
42  nRow2(0),
43  bImport(false),
44  bNative(false),
45  bSql(true),
47 {
48 }
49 
51  nCol1 (r.nCol1),
52  nRow1 (r.nRow1),
53  nCol2 (r.nCol2),
54  nRow2 (r.nRow2),
55  bImport (r.bImport),
56  aDBName (r.aDBName),
57  aStatement (r.aStatement),
58  bNative (r.bNative),
59  bSql (r.bSql),
60  nType (r.nType)
61 {
62 }
63 
65 {
66 }
67 
69 {
70  nCol1 = r.nCol1;
71  nRow1 = r.nRow1;
72  nCol2 = r.nCol2;
73  nRow2 = r.nRow2;
74  bImport = r.bImport;
75  aDBName = r.aDBName;
77  bNative = r.bNative;
78  bSql = r.bSql;
79  nType = r.nType;
80 
81  return *this;
82 }
83 
84 bool ScImportParam::operator==( const ScImportParam& rOther ) const
85 {
86  return( nCol1 == rOther.nCol1 &&
87  nRow1 == rOther.nRow1 &&
88  nCol2 == rOther.nCol2 &&
89  nRow2 == rOther.nRow2 &&
90  bImport == rOther.bImport &&
91  aDBName == rOther.aDBName &&
92  aStatement == rOther.aStatement &&
93  bNative == rOther.bNative &&
94  bSql == rOther.bSql &&
95  nType == rOther.nType );
96 
97  //TODO: are nQuerySh and pConnection equal ?
98 }
99 
100 // struct ScConsolidateParam:
101 
103 {
104  Clear();
105 }
106 
108 {
109  operator=(r);
110 }
111 
113 {
114 }
115 
117 {
118  pDataAreas.reset();
119  nDataAreaCount = 0;
120 }
121 
123 {
124  ClearDataAreas();
125 
126  nCol = 0;
127  nRow = 0;
128  nTab = 0;
129  bByCol = bByRow = bReferenceData = false;
131 }
132 
134 {
135  if (this != &r)
136  {
137  nCol = r.nCol;
138  nRow = r.nRow;
139  nTab = r.nTab;
140  bByCol = r.bByCol;
141  bByRow = r.bByRow;
143  eFunction = r.eFunction;
145  if ( r.nDataAreaCount > 0 )
146  {
148  pDataAreas.reset( new ScArea[nDataAreaCount] );
149  for ( sal_uInt16 i=0; i<nDataAreaCount; i++ )
150  pDataAreas[i] = r.pDataAreas[i];
151  }
152  else
153  pDataAreas.reset();
154  }
155  return *this;
156 }
157 
159 {
160  bool bEqual = (nCol == r.nCol)
161  && (nRow == r.nRow)
162  && (nTab == r.nTab)
163  && (bByCol == r.bByCol)
164  && (bByRow == r.bByRow)
167  && (eFunction == r.eFunction);
168 
169  if ( nDataAreaCount == 0 )
170  bEqual = bEqual && (pDataAreas == nullptr) && (r.pDataAreas == nullptr);
171  else
172  bEqual = bEqual && (pDataAreas != nullptr) && (r.pDataAreas != nullptr);
173 
174  if ( bEqual && (nDataAreaCount > 0) )
175  for ( sal_uInt16 i=0; i<nDataAreaCount && bEqual; i++ )
176  bEqual = pDataAreas[i] == r.pDataAreas[i];
177 
178  return bEqual;
179 }
180 
181 void ScConsolidateParam::SetAreas( std::unique_ptr<ScArea[]> pAreas, sal_uInt16 nCount )
182 {
183  pDataAreas = std::move(pAreas);
184  nDataAreaCount = nCount;
185 }
186 
187 // struct ScSolveParam
188 
190 {
191 }
192 
194  : aRefFormulaCell ( r.aRefFormulaCell ),
195  aRefVariableCell( r.aRefVariableCell ),
196  pStrTargetVal ( r.pStrTargetVal )
197 {
198 }
199 
201  const ScAddress& rVariableCell,
202  const OUString& rTargetValStr )
203  : aRefFormulaCell ( rFormulaCell ),
204  aRefVariableCell( rVariableCell ),
205  pStrTargetVal ( rTargetValStr )
206 {
207 }
208 
210 {
211 }
212 
214 {
218  return *this;
219 }
220 
222 {
223  bool bEqual = (aRefFormulaCell == r.aRefFormulaCell)
225 
226  if ( bEqual )
227  {
228  if ( !pStrTargetVal && !r.pStrTargetVal )
229  bEqual = true;
230  else if ( !pStrTargetVal || !r.pStrTargetVal )
231  bEqual = false;
232  else
233  bEqual = ( *pStrTargetVal == *(r.pStrTargetVal) );
234  }
235 
236  return bEqual;
237 }
238 
239 // struct ScTabOpParam
240 
242 
244  : aRefFormulaCell ( r.aRefFormulaCell ),
245  aRefFormulaEnd ( r.aRefFormulaEnd ),
246  aRefRowCell ( r.aRefRowCell ),
247  aRefColCell ( r.aRefColCell ),
248  meMode(r.meMode)
249 {
250 }
251 
253  const ScRefAddress& rFormulaEnd,
254  const ScRefAddress& rRowCell,
255  const ScRefAddress& rColCell,
256  Mode eMode )
257  : aRefFormulaCell ( rFormulaCell ),
258  aRefFormulaEnd ( rFormulaEnd ),
259  aRefRowCell ( rRowCell ),
260  aRefColCell ( rColCell ),
261  meMode(eMode)
262 {
263 }
264 
266 {
271  meMode = r.meMode;
272  return *this;
273 }
274 
276 {
277  return ( (aRefFormulaCell == r.aRefFormulaCell)
279  && (aRefRowCell == r.aRefRowCell)
280  && (aRefColCell == r.aRefColCell)
281  && (meMode == r.meMode) );
282 }
283 
284 OUString ScGlobal::GetAbsDocName( const OUString& rFileName,
285  const SfxObjectShell* pShell )
286 {
287  OUString aAbsName;
288  if (!pShell || !pShell->HasName())
289  { // maybe relative to document path working directory
290  INetURLObject aObj;
292  {
293  aObj.SetSmartURL(SvtPathOptions().GetWorkPath());
294  aObj.setFinalSlash(); // it IS a path
295  }
296  else
297  aObj.SetSmartURL("file:///tmp/document");
298  bool bWasAbs = true;
299  aAbsName = aObj.smartRel2Abs( rFileName, bWasAbs ).GetMainURL(INetURLObject::DecodeMechanism::NONE);
300  // returned string must be encoded because it's used directly to create SfxMedium
301  }
302  else
303  {
304  const SfxMedium* pMedium = pShell->GetMedium();
305  if ( pMedium )
306  {
307  bool bWasAbs = true;
308  aAbsName = pMedium->GetURLObject().smartRel2Abs( rFileName, bWasAbs ).GetMainURL(INetURLObject::DecodeMechanism::NONE);
309  }
310  else
311  { // This can't happen, but ...
312  // just to be sure to have the same encoding
313  INetURLObject aObj;
314  aObj.SetSmartURL( aAbsName );
316  }
317  }
318  return aAbsName;
319 }
320 
321 OUString ScGlobal::GetDocTabName( const OUString& rFileName,
322  const OUString& rTabName )
323 {
324  OUString aDocTab = "'" + rFileName;
325  sal_Int32 nPos = 1;
326  while( (nPos = aDocTab.indexOf( '\'', nPos )) != -1 )
327  { // escape Quotes
328  aDocTab = aDocTab.replaceAt( nPos, 0, "\\" );
329  nPos += 2;
330  }
331  aDocTab += "'" + OUStringChar(SC_COMPILER_FILE_TAB_SEP) + rTabName;
332  // "'Doc'#Tab"
333  return aDocTab;
334 }
335 
336 namespace
337 {
338 bool isEmptyString( const OUString& rStr )
339 {
340  if (rStr.isEmpty())
341  return true;
342  else if (rStr[0] == ' ')
343  {
344  const sal_Unicode* p = rStr.getStr() + 1;
345  const sal_Unicode* const pStop = p - 1 + rStr.getLength();
346  while (p < pStop && *p == ' ')
347  ++p;
348  if (p == pStop)
349  return true;
350  }
351  return false;
352 }
353 }
354 
355 double ScGlobal::ConvertStringToValue( const OUString& rStr, const ScCalcConfig& rConfig,
356  FormulaError & rError, FormulaError nStringNoValueError,
357  SvNumberFormatter* pFormatter, SvNumFormatType & rCurFmtType )
358 {
359  // We keep ScCalcConfig::StringConversion::LOCALE default until
360  // we provide a friendly way to convert string numbers into numbers in the UI.
361 
362  double fValue = 0.0;
363  if (nStringNoValueError == FormulaError::CellNoValue)
364  {
365  // Requested that all strings result in 0, error handled by caller.
366  rError = nStringNoValueError;
367  return fValue;
368  }
369 
370  switch (rConfig.meStringConversion)
371  {
373  rError = nStringNoValueError;
374  return fValue;
376  return fValue;
378  {
379  if (rConfig.mbEmptyStringAsZero)
380  {
381  // The number scanner does not accept empty strings or strings
382  // containing only spaces, be on par in these cases with what was
383  // accepted in OOo and is in AOO (see also the
384  // StringConversion::UNAMBIGUOUS branch) and convert to 0 to prevent
385  // interoperability nightmares.
386 
387  if (isEmptyString( rStr))
388  return fValue;
389  }
390 
391  if (!pFormatter)
392  goto Label_fallback_to_unambiguous;
393 
394  sal_uInt32 nFIndex = 0;
395  if (!pFormatter->IsNumberFormat(rStr, nFIndex, fValue))
396  {
397  rError = nStringNoValueError;
398  fValue = 0.0;
399  }
400  return fValue;
401  }
402  break;
404 Label_fallback_to_unambiguous:
405  {
406  if (!rConfig.mbEmptyStringAsZero)
407  {
408  if (isEmptyString( rStr))
409  {
410  rError = nStringNoValueError;
411  return fValue;
412  }
413  }
414  }
415  // continue below, pulled from switch case for better readability
416  break;
417  }
418 
419  rtl_math_ConversionStatus eStatus;
420  sal_Int32 nParseEnd;
421  // Decimal and group separator 0 => only integer and possibly exponent,
422  // stops at first non-digit non-sign.
423  fValue = ::rtl::math::stringToDouble( rStr, 0, 0, &eStatus, &nParseEnd);
424  sal_Int32 nLen = rStr.getLength();
425  if (eStatus == rtl_math_ConversionStatus_Ok && nParseEnd < nLen)
426  {
427  // Not at string end, check for trailing blanks or switch to date or
428  // time parsing or bail out.
429  const sal_Unicode* const pStart = rStr.getStr();
430  const sal_Unicode* p = pStart + nParseEnd;
431  const sal_Unicode* const pStop = pStart + nLen;
432  switch (*p++)
433  {
434  case ' ':
435  while (p < pStop && *p == ' ')
436  ++p;
437  if (p < pStop)
438  rError = nStringNoValueError;
439  break;
440  case '-':
441  case ':':
442  {
443  bool bDate = (*(p-1) == '-');
444  enum State { year = 0, month, day, hour, minute, second, fraction, done, blank, stop };
445  sal_Int32 nUnit[done] = {0,0,0,0,0,0,0};
446  const sal_Int32 nLimit[done] = {0,12,31,0,59,59,0};
447  State eState = (bDate ? month : minute);
448  rCurFmtType = (bDate ? SvNumFormatType::DATE : SvNumFormatType::TIME);
449  nUnit[eState-1] = rStr.copy( 0, nParseEnd).toInt32();
450  const sal_Unicode* pLastStart = p;
451  // Ensure there's no preceding sign. Negative dates
452  // currently aren't handled correctly. Also discard
453  // +CCYY-MM-DD
454  p = pStart;
455  while (p < pStop && *p == ' ')
456  ++p;
457  if (p < pStop && !rtl::isAsciiDigit(*p))
458  rError = nStringNoValueError;
459  p = pLastStart;
460  while (p < pStop && rError == FormulaError::NONE && eState < blank)
461  {
462  if (eState == minute)
463  rCurFmtType |= SvNumFormatType::TIME;
464  if (rtl::isAsciiDigit(*p))
465  {
466  // Maximum 2 digits per unit, except fractions.
467  if (p - pLastStart >= 2 && eState != fraction)
468  rError = nStringNoValueError;
469  }
470  else if (p > pLastStart)
471  {
472  // We had at least one digit.
473  if (eState < done)
474  {
475  nUnit[eState] = rStr.copy( pLastStart - pStart, p - pLastStart).toInt32();
476  if (nLimit[eState] && nLimit[eState] < nUnit[eState])
477  rError = nStringNoValueError;
478  }
479  pLastStart = p + 1; // hypothetical next start
480  // Delimiters must match, a trailing delimiter
481  // yields an invalid date/time.
482  switch (eState)
483  {
484  case month:
485  // Month must be followed by separator and
486  // day, no trailing blanks.
487  if (*p != '-' || (p+1 == pStop))
488  rError = nStringNoValueError;
489  break;
490  case day:
491  if ((*p != 'T' || (p+1 == pStop)) && *p != ' ')
492  rError = nStringNoValueError;
493  // Take one blank as a valid delimiter
494  // between date and time.
495  break;
496  case hour:
497  // Hour must be followed by separator and
498  // minute, no trailing blanks.
499  if (*p != ':' || (p+1 == pStop))
500  rError = nStringNoValueError;
501  break;
502  case minute:
503  if ((*p != ':' || (p+1 == pStop)) && *p != ' ')
504  rError = nStringNoValueError;
505  if (*p == ' ')
506  eState = done;
507  break;
508  case second:
509  if (((*p != ',' && *p != '.') || (p+1 == pStop)) && *p != ' ')
510  rError = nStringNoValueError;
511  if (*p == ' ')
512  eState = done;
513  break;
514  case fraction:
515  eState = done;
516  break;
517  default:
518  rError = nStringNoValueError;
519  break;
520  }
521  eState = static_cast<State>(eState + 1);
522  }
523  else
524  rError = nStringNoValueError;
525  ++p;
526  }
527  if (eState == blank)
528  {
529  while (p < pStop && *p == ' ')
530  ++p;
531  if (p < pStop)
532  rError = nStringNoValueError;
533  eState = stop;
534  }
535 
536  // Month without day, or hour without minute.
537  if (eState == month || (eState == day && p <= pLastStart) ||
538  eState == hour || (eState == minute && p <= pLastStart))
539  rError = nStringNoValueError;
540 
541  if (rError == FormulaError::NONE)
542  {
543  // Catch the very last unit at end of string.
544  if (p > pLastStart && eState < done)
545  {
546  nUnit[eState] = rStr.copy( pLastStart - pStart, p - pLastStart).toInt32();
547  if (nLimit[eState] && nLimit[eState] < nUnit[eState])
548  rError = nStringNoValueError;
549  }
550  if (bDate && nUnit[hour] > 23)
551  rError = nStringNoValueError;
552  if (rError == FormulaError::NONE)
553  {
554  if (bDate && nUnit[day] == 0)
555  nUnit[day] = 1;
556  double fFraction = (nUnit[fraction] <= 0 ? 0.0 :
557  ::rtl::math::pow10Exp( nUnit[fraction],
558  static_cast<int>( -ceil( log10( static_cast<double>( nUnit[fraction]))))));
559  if (!bDate)
560  fValue = 0.0;
561  else
562  {
563  Date aDate(
564  sal::static_int_cast<sal_Int16>(nUnit[day]),
565  sal::static_int_cast<sal_Int16>(nUnit[month]),
566  sal::static_int_cast<sal_Int16>(nUnit[year]));
567  if (!aDate.IsValidDate())
568  rError = nStringNoValueError;
569  else
570  {
571  if (pFormatter)
572  fValue = aDate - pFormatter->GetNullDate();
573  else
574  {
575  SAL_WARN("sc.core","ScGlobal::ConvertStringToValue - fixed null date");
576  static Date aDefaultNullDate( 30, 12, 1899);
577  fValue = aDate - aDefaultNullDate;
578  }
579  }
580  }
581  fValue += ((nUnit[hour] * 3600) + (nUnit[minute] * 60) + nUnit[second] + fFraction) / 86400.0;
582  }
583  }
584  }
585  break;
586  default:
587  rError = nStringNoValueError;
588  }
589  if (rError != FormulaError::NONE)
590  fValue = 0.0;
591  }
592  return fValue;
593 }
594 
595 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool operator==(const ScImportParam &r) const
Definition: global2.cxx:84
State
static SC_DLLPUBLIC OUString GetDocTabName(const OUString &rFileName, const OUString &rTabName)
Definition: global2.cxx:321
bool IsValidDate() const
OUString aDBName
Definition: global.hxx:455
sal_Int32 month
=1+"1" gives 2, but =1+"1.000" or =1+"x" give VALUE!
struct _ADOColumn Column
void SetAreas(std::unique_ptr< ScArea[]> pAreas, sal_uInt16 nCount)
Definition: global2.cxx:181
sal_uInt16 nDataAreaCount
Definition: global.hxx:893
static double ConvertStringToValue(const OUString &rStr, const ScCalcConfig &rConfig, FormulaError &rError, FormulaError nStringNoValueError, SvNumberFormatter *pFormatter, SvNumFormatType &rCurFmtType)
Convert string content to numeric value.
Definition: global2.cxx:355
std::unique_ptr< ScArea[]> pDataAreas
Definition: global.hxx:894
SCROW nRow2
Definition: global.hxx:453
bool operator==(const ScTabOpParam &r) const
Definition: global2.cxx:275
sal_uInt16 sal_Unicode
bool setFinalSlash()
=1+"1" or =1+"x" give 1
static bool IsFuzzing()
ScImportParam & operator=(const ScImportParam &r)
Definition: global2.cxx:68
SCCOL nCol2
Definition: global.hxx:452
ScRefAddress aRefRowCell
Definition: paramisc.hxx:52
StringConversion meStringConversion
Definition: calcconfig.hxx:54
bool operator==(const ScSolveParam &r) const
Definition: global2.cxx:221
ScAddress aRefVariableCell
Definition: paramisc.hxx:29
SCROW nRow1
Definition: global.hxx:451
ColorMode meMode
void ClearDataAreas()
Definition: global2.cxx:116
std::optional< OUString > pStrTargetVal
Definition: paramisc.hxx:30
bool operator==(const ScConsolidateParam &r) const
Definition: global2.cxx:158
static SC_DLLPUBLIC OUString GetAbsDocName(const OUString &rFileName, const SfxObjectShell *pShell)
Definition: global2.cxx:284
OUString aStatement
Definition: global.hxx:456
Parameter for data table aka multiple operations.
Definition: paramisc.hxx:46
int i
=1+"1.000" may be 2 or 1001 ... =1+"x" gives VALUE!
ScRefAddress aRefFormulaCell
Definition: paramisc.hxx:50
bool bNative
Definition: global.hxx:457
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
ScSolveParam & operator=(const ScSolveParam &r)
Definition: global2.cxx:213
SvNumFormatType
def stop
bool HasName() const
ScTabOpParam & operator=(const ScTabOpParam &r)
Definition: global2.cxx:265
FormulaError
Configuration options for formula interpreter.
Definition: calcconfig.hxx:43
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
sal_Int32 day
sal_uInt8 nType
Definition: global.hxx:459
ScRefAddress aRefColCell
Definition: paramisc.hxx:53
ScSubTotalFunc eFunction
Definition: global.hxx:892
const INetURLObject & GetURLObject() const
void * p
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:401
bool bImport
Definition: global.hxx:454
SCCOL nCol1
Definition: global.hxx:450
#define SC_COMPILER_FILE_TAB_SEP
Definition: compiler.hxx:83
ScAddress aRefFormulaCell
Definition: paramisc.hxx:28
=1+"1" or =1+"x" give VALUE!
#define SAL_WARN(area, stream)
ScRefAddress aRefFormulaEnd
Definition: paramisc.hxx:51
sal_Int32 year
bool mbEmptyStringAsZero
Definition: calcconfig.hxx:55
const Date & GetNullDate() const
INetURLObject smartRel2Abs(OUString const &rTheRelURIRef, bool &rWasAbsolute, bool bIgnoreFragment=false, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8, bool bRelativeNonURIs=false, FSysStyle eStyle=FSysStyle::Detect) const
ScConsolidateParam & operator=(const ScConsolidateParam &r)
Definition: global2.cxx:133
sal_uInt16 nPos
bool SetSmartURL(OUString const &rTheAbsURIRef, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8, FSysStyle eStyle=FSysStyle::Detect)
SfxMedium * GetMedium() const