Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / sc / source / core / data / global2.cxx
blob4a9237a38f9fd4953a3800d7105b330ad749f376
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sfx2/docfile.hxx>
21 #include <sfx2/objsh.hxx>
22 #include <comphelper/configuration.hxx>
23 #include <unotools/pathoptions.hxx>
24 #include <tools/urlobj.hxx>
25 #include <svl/numformat.hxx>
26 #include <svl/zforlist.hxx>
27 #include <formula/errorcodes.hxx>
28 #include <sal/log.hxx>
29 #include <rtl/character.hxx>
30 #include <rtl/math.hxx>
31 #include <o3tl/string_view.hxx>
33 #include <global.hxx>
34 #include <rangeutl.hxx>
35 #include <compiler.hxx>
36 #include <paramisc.hxx>
37 #include <calcconfig.hxx>
38 #include <interpretercontext.hxx>
40 // struct ScImportParam:
42 ScImportParam::ScImportParam() :
43 nCol1(0),
44 nRow1(0),
45 nCol2(0),
46 nRow2(0),
47 bImport(false),
48 bNative(false),
49 bSql(true),
50 nType(ScDbTable)
54 ScImportParam::ScImportParam( const ScImportParam& r ) :
55 nCol1 (r.nCol1),
56 nRow1 (r.nRow1),
57 nCol2 (r.nCol2),
58 nRow2 (r.nRow2),
59 bImport (r.bImport),
60 aDBName (r.aDBName),
61 aStatement (r.aStatement),
62 bNative (r.bNative),
63 bSql (r.bSql),
64 nType (r.nType)
68 ScImportParam::~ScImportParam()
72 ScImportParam& ScImportParam::operator=( const ScImportParam& r )
74 nCol1 = r.nCol1;
75 nRow1 = r.nRow1;
76 nCol2 = r.nCol2;
77 nRow2 = r.nRow2;
78 bImport = r.bImport;
79 aDBName = r.aDBName;
80 aStatement = r.aStatement;
81 bNative = r.bNative;
82 bSql = r.bSql;
83 nType = r.nType;
85 return *this;
88 bool ScImportParam::operator==( const ScImportParam& rOther ) const
90 return( nCol1 == rOther.nCol1 &&
91 nRow1 == rOther.nRow1 &&
92 nCol2 == rOther.nCol2 &&
93 nRow2 == rOther.nRow2 &&
94 bImport == rOther.bImport &&
95 aDBName == rOther.aDBName &&
96 aStatement == rOther.aStatement &&
97 bNative == rOther.bNative &&
98 bSql == rOther.bSql &&
99 nType == rOther.nType );
101 //TODO: are nQuerySh and pConnection equal ?
104 // struct ScConsolidateParam:
106 ScConsolidateParam::ScConsolidateParam()
108 Clear();
111 ScConsolidateParam::ScConsolidateParam( const ScConsolidateParam& r )
113 operator=(r);
116 ScConsolidateParam::~ScConsolidateParam()
120 void ScConsolidateParam::ClearDataAreas()
122 pDataAreas.reset();
123 nDataAreaCount = 0;
126 void ScConsolidateParam::Clear()
128 ClearDataAreas();
130 nCol = 0;
131 nRow = 0;
132 nTab = 0;
133 bByCol = bByRow = bReferenceData = false;
134 eFunction = SUBTOTAL_FUNC_SUM;
137 ScConsolidateParam& ScConsolidateParam::operator=( const ScConsolidateParam& r )
139 if (this != &r)
141 nCol = r.nCol;
142 nRow = r.nRow;
143 nTab = r.nTab;
144 bByCol = r.bByCol;
145 bByRow = r.bByRow;
146 bReferenceData = r.bReferenceData;
147 eFunction = r.eFunction;
148 nDataAreaCount = r.nDataAreaCount;
149 if ( r.nDataAreaCount > 0 )
151 nDataAreaCount = r.nDataAreaCount;
152 pDataAreas.reset( new ScArea[nDataAreaCount] );
153 for ( sal_uInt16 i=0; i<nDataAreaCount; i++ )
154 pDataAreas[i] = r.pDataAreas[i];
156 else
157 pDataAreas.reset();
159 return *this;
162 bool ScConsolidateParam::operator==( const ScConsolidateParam& r ) const
164 bool bEqual = (nCol == r.nCol)
165 && (nRow == r.nRow)
166 && (nTab == r.nTab)
167 && (bByCol == r.bByCol)
168 && (bByRow == r.bByRow)
169 && (bReferenceData == r.bReferenceData)
170 && (nDataAreaCount == r.nDataAreaCount)
171 && (eFunction == r.eFunction);
173 if ( nDataAreaCount == 0 )
174 bEqual = bEqual && (pDataAreas == nullptr) && (r.pDataAreas == nullptr);
175 else
176 bEqual = bEqual && (pDataAreas != nullptr) && (r.pDataAreas != nullptr);
178 if ( bEqual && (nDataAreaCount > 0) )
179 for ( sal_uInt16 i=0; i<nDataAreaCount && bEqual; i++ )
180 bEqual = pDataAreas[i] == r.pDataAreas[i];
182 return bEqual;
185 void ScConsolidateParam::SetAreas( std::unique_ptr<ScArea[]> pAreas, sal_uInt16 nCount )
187 pDataAreas = std::move(pAreas);
188 nDataAreaCount = nCount;
191 // struct ScSolveParam
193 ScSolveParam::ScSolveParam()
197 ScSolveParam::ScSolveParam( const ScSolveParam& r )
198 : aRefFormulaCell ( r.aRefFormulaCell ),
199 aRefVariableCell( r.aRefVariableCell ),
200 pStrTargetVal ( r.pStrTargetVal )
204 ScSolveParam::ScSolveParam( const ScAddress& rFormulaCell,
205 const ScAddress& rVariableCell,
206 const OUString& rTargetValStr )
207 : aRefFormulaCell ( rFormulaCell ),
208 aRefVariableCell( rVariableCell ),
209 pStrTargetVal ( rTargetValStr )
213 ScSolveParam::~ScSolveParam()
217 ScSolveParam& ScSolveParam::operator=( const ScSolveParam& r )
219 aRefFormulaCell = r.aRefFormulaCell;
220 aRefVariableCell = r.aRefVariableCell;
221 pStrTargetVal = r.pStrTargetVal;
222 return *this;
225 bool ScSolveParam::operator==( const ScSolveParam& r ) const
227 bool bEqual = (aRefFormulaCell == r.aRefFormulaCell)
228 && (aRefVariableCell == r.aRefVariableCell);
230 if ( bEqual )
232 if ( !pStrTargetVal && !r.pStrTargetVal )
233 bEqual = true;
234 else if ( !pStrTargetVal || !r.pStrTargetVal )
235 bEqual = false;
236 else
237 bEqual = ( *pStrTargetVal == *(r.pStrTargetVal) );
240 return bEqual;
243 // struct ScTabOpParam
245 ScTabOpParam::ScTabOpParam() : meMode(Column) {}
247 ScTabOpParam::ScTabOpParam( const ScTabOpParam& r )
248 : aRefFormulaCell ( r.aRefFormulaCell ),
249 aRefFormulaEnd ( r.aRefFormulaEnd ),
250 aRefRowCell ( r.aRefRowCell ),
251 aRefColCell ( r.aRefColCell ),
252 meMode(r.meMode)
256 ScTabOpParam::ScTabOpParam( const ScRefAddress& rFormulaCell,
257 const ScRefAddress& rFormulaEnd,
258 const ScRefAddress& rRowCell,
259 const ScRefAddress& rColCell,
260 Mode eMode )
261 : aRefFormulaCell ( rFormulaCell ),
262 aRefFormulaEnd ( rFormulaEnd ),
263 aRefRowCell ( rRowCell ),
264 aRefColCell ( rColCell ),
265 meMode(eMode)
269 ScTabOpParam& ScTabOpParam::operator=( const ScTabOpParam& r )
271 aRefFormulaCell = r.aRefFormulaCell;
272 aRefFormulaEnd = r.aRefFormulaEnd;
273 aRefRowCell = r.aRefRowCell;
274 aRefColCell = r.aRefColCell;
275 meMode = r.meMode;
276 return *this;
279 bool ScTabOpParam::operator==( const ScTabOpParam& r ) const
281 return ( (aRefFormulaCell == r.aRefFormulaCell)
282 && (aRefFormulaEnd == r.aRefFormulaEnd)
283 && (aRefRowCell == r.aRefRowCell)
284 && (aRefColCell == r.aRefColCell)
285 && (meMode == r.meMode) );
288 OUString ScGlobal::GetAbsDocName( const OUString& rFileName,
289 const SfxObjectShell* pShell )
291 OUString aAbsName;
292 if (!pShell || !pShell->HasName())
293 { // maybe relative to document path working directory
294 INetURLObject aObj;
295 if (!comphelper::IsFuzzing())
297 aObj.SetSmartURL(SvtPathOptions().GetWorkPath());
298 aObj.setFinalSlash(); // it IS a path
300 else
301 aObj.SetSmartURL(u"file:///tmp/document");
302 bool bWasAbs = true;
303 aAbsName = aObj.smartRel2Abs( rFileName, bWasAbs ).GetMainURL(INetURLObject::DecodeMechanism::NONE);
304 // returned string must be encoded because it's used directly to create SfxMedium
306 else
308 const SfxMedium* pMedium = pShell->GetMedium();
309 if ( pMedium )
311 bool bWasAbs = true;
312 aAbsName = pMedium->GetURLObject().smartRel2Abs( rFileName, bWasAbs ).GetMainURL(INetURLObject::DecodeMechanism::NONE);
314 else
315 { // This can't happen, but ...
316 // just to be sure to have the same encoding
317 INetURLObject aObj;
318 aObj.SetSmartURL( aAbsName );
319 aAbsName = aObj.GetMainURL(INetURLObject::DecodeMechanism::NONE);
322 return aAbsName;
325 OUString ScGlobal::GetDocTabName( std::u16string_view rFileName,
326 std::u16string_view rTabName )
328 OUString aDocTab(rFileName);
329 // "'Doc'#Tab"
330 aDocTab = "'" + aDocTab.replaceAll(u"'", u"\\'") + "'" + OUStringChar(SC_COMPILER_FILE_TAB_SEP) + rTabName;
331 return aDocTab;
334 namespace
336 bool isEmptyString( const OUString& rStr )
338 if (rStr.isEmpty())
339 return true;
340 else if (rStr[0] == ' ')
342 const sal_Unicode* p = rStr.getStr() + 1;
343 const sal_Unicode* const pStop = p - 1 + rStr.getLength();
344 while (p < pStop && *p == ' ')
345 ++p;
346 if (p == pStop)
347 return true;
349 return false;
353 double ScGlobal::ConvertStringToValue( const OUString& rStr, const ScCalcConfig& rConfig,
354 FormulaError & rError, FormulaError nStringNoValueError,
355 ScInterpreterContext& rContext, SvNumFormatType & rCurFmtType )
357 // We keep ScCalcConfig::StringConversion::LOCALE default until
358 // we provide a friendly way to convert string numbers into numbers in the UI.
360 double fValue = 0.0;
361 if (nStringNoValueError == FormulaError::CellNoValue)
363 // Requested that all strings result in 0, error handled by caller.
364 rError = nStringNoValueError;
365 return fValue;
368 switch (rConfig.meStringConversion)
370 case ScCalcConfig::StringConversion::ILLEGAL:
371 rError = nStringNoValueError;
372 return fValue;
373 case ScCalcConfig::StringConversion::ZERO:
374 return fValue;
375 case ScCalcConfig::StringConversion::LOCALE:
377 if (rConfig.mbEmptyStringAsZero)
379 // The number scanner does not accept empty strings or strings
380 // containing only spaces, be on par in these cases with what was
381 // accepted in OOo and is in AOO (see also the
382 // StringConversion::UNAMBIGUOUS branch) and convert to 0 to prevent
383 // interoperability nightmares.
385 if (isEmptyString( rStr))
386 return fValue;
389 sal_uInt32 nFIndex = 0;
390 if (!rContext.NFIsNumberFormat(rStr, nFIndex, fValue))
392 rError = nStringNoValueError;
393 fValue = 0.0;
395 return fValue;
397 break;
398 case ScCalcConfig::StringConversion::UNAMBIGUOUS:
400 if (!rConfig.mbEmptyStringAsZero)
402 if (isEmptyString( rStr))
404 rError = nStringNoValueError;
405 return fValue;
409 // continue below, pulled from switch case for better readability
410 break;
413 rtl_math_ConversionStatus eStatus;
414 sal_Int32 nParseEnd;
415 // Decimal and group separator 0 => only integer and possibly exponent,
416 // stops at first non-digit non-sign.
417 fValue = ::rtl::math::stringToDouble( rStr, 0, 0, &eStatus, &nParseEnd);
418 sal_Int32 nLen = rStr.getLength();
419 if (eStatus == rtl_math_ConversionStatus_Ok && nParseEnd < nLen)
421 // Not at string end, check for trailing blanks or switch to date or
422 // time parsing or bail out.
423 const sal_Unicode* const pStart = rStr.getStr();
424 const sal_Unicode* p = pStart + nParseEnd;
425 const sal_Unicode* const pStop = pStart + nLen;
426 switch (*p++)
428 case ' ':
429 while (p < pStop && *p == ' ')
430 ++p;
431 if (p < pStop)
432 rError = nStringNoValueError;
433 break;
434 case '-':
435 case ':':
437 bool bDate = (*(p-1) == '-');
438 enum State { year = 0, month, day, hour, minute, second, fraction, done, blank, stop };
439 sal_Int32 nUnit[done] = {0,0,0,0,0,0,0};
440 const sal_Int32 nLimit[done] = {0,12,31,0,59,59,0};
441 State eState = (bDate ? month : minute);
442 rCurFmtType = (bDate ? SvNumFormatType::DATE : SvNumFormatType::TIME);
443 nUnit[eState-1] = o3tl::toInt32(rStr.subView( 0, nParseEnd));
444 const sal_Unicode* pLastStart = p;
445 // Ensure there's no preceding sign. Negative dates
446 // currently aren't handled correctly. Also discard
447 // +CCYY-MM-DD
448 p = pStart;
449 while (p < pStop && *p == ' ')
450 ++p;
451 if (p < pStop && !rtl::isAsciiDigit(*p))
452 rError = nStringNoValueError;
453 p = pLastStart;
454 while (p < pStop && rError == FormulaError::NONE && eState < blank)
456 if (eState == minute)
457 rCurFmtType |= SvNumFormatType::TIME;
458 if (rtl::isAsciiDigit(*p))
460 // Maximum 2 digits per unit, except fractions.
461 if (p - pLastStart >= 2 && eState != fraction)
462 rError = nStringNoValueError;
464 else if (p > pLastStart)
466 // We had at least one digit.
467 if (eState < done)
469 nUnit[eState] = o3tl::toInt32(rStr.subView( pLastStart - pStart, p - pLastStart));
470 if (nLimit[eState] && nLimit[eState] < nUnit[eState])
471 rError = nStringNoValueError;
473 pLastStart = p + 1; // hypothetical next start
474 // Delimiters must match, a trailing delimiter
475 // yields an invalid date/time.
476 switch (eState)
478 case month:
479 // Month must be followed by separator and
480 // day, no trailing blanks.
481 if (*p != '-' || (p+1 == pStop))
482 rError = nStringNoValueError;
483 break;
484 case day:
485 if ((*p != 'T' || (p+1 == pStop)) && *p != ' ')
486 rError = nStringNoValueError;
487 // Take one blank as a valid delimiter
488 // between date and time.
489 break;
490 case hour:
491 // Hour must be followed by separator and
492 // minute, no trailing blanks.
493 if (*p != ':' || (p+1 == pStop))
494 rError = nStringNoValueError;
495 break;
496 case minute:
497 if ((*p != ':' || (p+1 == pStop)) && *p != ' ')
498 rError = nStringNoValueError;
499 if (*p == ' ')
500 eState = done;
501 break;
502 case second:
503 if (((*p != ',' && *p != '.') || (p+1 == pStop)) && *p != ' ')
504 rError = nStringNoValueError;
505 if (*p == ' ')
506 eState = done;
507 break;
508 case fraction:
509 eState = done;
510 break;
511 default:
512 rError = nStringNoValueError;
513 break;
515 eState = static_cast<State>(eState + 1);
517 else
518 rError = nStringNoValueError;
519 ++p;
521 if (eState == blank)
523 while (p < pStop && *p == ' ')
524 ++p;
525 if (p < pStop)
526 rError = nStringNoValueError;
527 eState = stop;
530 // Month without day, or hour without minute.
531 if (eState == month || (eState == day && p <= pLastStart) ||
532 eState == hour || (eState == minute && p <= pLastStart))
533 rError = nStringNoValueError;
535 if (rError == FormulaError::NONE)
537 // Catch the very last unit at end of string.
538 if (p > pLastStart && eState < done)
540 nUnit[eState] = o3tl::toInt32(rStr.subView( pLastStart - pStart, p - pLastStart));
541 if (nLimit[eState] && nLimit[eState] < nUnit[eState])
542 rError = nStringNoValueError;
544 if (bDate && nUnit[hour] > 23)
545 rError = nStringNoValueError;
546 if (rError == FormulaError::NONE)
548 if (bDate && nUnit[day] == 0)
549 nUnit[day] = 1;
550 double fFraction = (nUnit[fraction] <= 0 ? 0.0 :
551 ::rtl::math::pow10Exp( nUnit[fraction],
552 static_cast<int>( -ceil( log10( static_cast<double>( nUnit[fraction]))))));
553 if (!bDate)
554 fValue = 0.0;
555 else
557 Date aDate(
558 sal::static_int_cast<sal_Int16>(nUnit[day]),
559 sal::static_int_cast<sal_Int16>(nUnit[month]),
560 sal::static_int_cast<sal_Int16>(nUnit[year]));
561 if (!aDate.IsValidDate())
562 rError = nStringNoValueError;
563 else
565 fValue = aDate - rContext.NFGetNullDate();
568 fValue += ((nUnit[hour] * 3600) + (nUnit[minute] * 60) + nUnit[second] + fFraction) / 86400.0;
572 break;
573 default:
574 rError = nStringNoValueError;
576 if (rError != FormulaError::NONE)
577 fValue = 0.0;
579 return fValue;
582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */