LCOV - code coverage report
Current view: top level - libreoffice/basic/source/sbx - sbxscan.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 52 374 13.9 %
Date: 2012-12-17 Functions: 3 12 25.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 <tools/errcode.hxx>
      21             : #include <basic/sbx.hxx>
      22             : #include "sbxconv.hxx"
      23             : 
      24             : #include "unotools/syslocale.hxx"
      25             : 
      26             : #if defined ( UNX )
      27             : #include <stdlib.h>
      28             : #endif
      29             : 
      30             : #include <vcl/svapp.hxx>
      31             : #include <math.h>
      32             : #include <string.h>
      33             : #include <ctype.h>
      34             : 
      35             : #include "sbxres.hxx"
      36             : #include <basic/sbxbase.hxx>
      37             : #include <basic/sbxfac.hxx>
      38             : #include <basic/sbxform.hxx>
      39             : #include <svtools/svtools.hrc>
      40             : 
      41             : #include "basrid.hxx"
      42             : #include "date.hxx"
      43             : #include "runtime.hxx"
      44             : 
      45             : #include <rtl/strbuf.hxx>
      46             : #include <svl/zforlist.hxx>
      47             : #include <comphelper/processfactory.hxx>
      48             : 
      49             : 
      50           8 : void ImpGetIntntlSep( sal_Unicode& rcDecimalSep, sal_Unicode& rcThousandSep )
      51             : {
      52           8 :     SvtSysLocale aSysLocale;
      53           8 :     const LocaleDataWrapper& rData = aSysLocale.GetLocaleData();
      54           8 :     rcDecimalSep = rData.getNumDecimalSep()[0];
      55           8 :     rcThousandSep = rData.getNumThousandSep()[0];
      56           8 : }
      57             : 
      58             : // scanning a string according to BASIC-conventions
      59             : // but exponent may also be a D, so data type is SbxDOUBLED
      60             : // conversion error if data type is fixed and it doesn't fit
      61             : 
      62           0 : SbxError ImpScan( const ::rtl::OUString& rWSrc, double& nVal, SbxDataType& rType,
      63             :                   sal_uInt16* pLen, bool bAllowIntntl, bool bOnlyIntntl )
      64             : {
      65           0 :     ::rtl::OString aBStr( ::rtl::OUStringToOString( rWSrc, RTL_TEXTENCODING_ASCII_US ) );
      66             : 
      67             :     char cIntntlComma, cIntntl1000;
      68           0 :     char cNonIntntlComma = '.';
      69             : 
      70           0 :     sal_Unicode cDecimalSep, cThousandSep = 0;
      71           0 :     if( bAllowIntntl || bOnlyIntntl )
      72             :     {
      73           0 :         ImpGetIntntlSep( cDecimalSep, cThousandSep );
      74           0 :         cIntntlComma = (char)cDecimalSep;
      75           0 :         cIntntl1000 = (char)cThousandSep;
      76             :     }
      77             : 
      78             :     else
      79             :     {
      80           0 :         cIntntlComma = cNonIntntlComma;
      81           0 :         cIntntl1000 = cNonIntntlComma;
      82             :     }
      83             : 
      84           0 :     if( bOnlyIntntl )
      85             :     {
      86           0 :         cNonIntntlComma = cIntntlComma;
      87           0 :         cIntntl1000 = (char)cThousandSep;
      88             :     }
      89             : 
      90           0 :     const char* pStart = aBStr.getStr();
      91           0 :     const char* p = pStart;
      92           0 :     char buf[ 80 ], *q = buf;
      93           0 :     bool bRes = true;
      94           0 :     bool bMinus = false;
      95           0 :     nVal = 0;
      96           0 :     SbxDataType eScanType = SbxSINGLE;
      97           0 :     while( *p &&( *p == ' ' || *p == '\t' ) ) p++;
      98           0 :     if( *p == '-' )
      99           0 :         p++, bMinus = true;
     100           0 :     if( isdigit( *p ) ||( (*p == cNonIntntlComma || *p == cIntntlComma ||
     101           0 :             *p == cIntntl1000) && isdigit( *(p+1 ) ) ) )
     102             :     {
     103           0 :         short exp = 0;
     104           0 :         short comma = 0;
     105           0 :         short ndig = 0;
     106           0 :         short ncdig = 0;    // number of digits after decimal point
     107           0 :         rtl::OStringBuffer aSearchStr(RTL_CONSTASCII_STRINGPARAM("0123456789DEde"));
     108           0 :         aSearchStr.append(cNonIntntlComma);
     109           0 :         if( cIntntlComma != cNonIntntlComma )
     110           0 :             aSearchStr.append(cIntntlComma);
     111           0 :         if( bOnlyIntntl )
     112           0 :             aSearchStr.append(cIntntl1000);
     113           0 :         const char* pSearchStr = aSearchStr.getStr();
     114           0 :         while( strchr( pSearchStr, *p ) && *p )
     115             :         {
     116           0 :             if( bOnlyIntntl && *p == cIntntl1000 )
     117             :             {
     118           0 :                 p++;
     119           0 :                 continue;
     120             :             }
     121             : 
     122           0 :             if( *p == cNonIntntlComma || *p == cIntntlComma )
     123             :             {
     124             :                 // always insert '.' so that atof works
     125           0 :                 p++;
     126           0 :                 if( ++comma > 1 )
     127           0 :                     continue;
     128             :                 else
     129           0 :                     *q++ = '.';
     130             :             }
     131           0 :             else if( strchr( "DdEe", *p ) )
     132             :             {
     133           0 :                 if( ++exp > 1 )
     134             :                 {
     135           0 :                     p++; continue;
     136             :                 }
     137           0 :                 if( toupper( *p ) == 'D' )
     138           0 :                     eScanType = SbxDOUBLE;
     139           0 :                 *q++ = 'E'; p++;
     140             : 
     141           0 :                 if( *p == '+' )
     142           0 :                     p++;
     143             :                 else
     144           0 :                 if( *p == '-' )
     145           0 :                     *q++ = *p++;
     146             :             }
     147             :             else
     148             :             {
     149           0 :                 *q++ = *p++;
     150           0 :                 if( comma && !exp ) ncdig++;
     151             :             }
     152           0 :             if( !exp ) ndig++;
     153             :         }
     154           0 :         *q = 0;
     155             : 
     156           0 :         if( comma > 1 || exp > 1 )
     157           0 :             bRes = false;
     158             : 
     159           0 :         if( !comma && !exp )
     160             :         {
     161           0 :             if( nVal >= SbxMININT && nVal <= SbxMAXINT )
     162           0 :                 eScanType = SbxINTEGER;
     163           0 :             else if( nVal >= SbxMINLNG && nVal <= SbxMAXLNG )
     164           0 :                 eScanType = SbxLONG;
     165             :         }
     166             : 
     167           0 :         nVal = atof( buf );
     168           0 :         ndig = ndig - comma;
     169             :         // too many numbers for SINGLE?
     170           0 :         if( ndig > 15 || ncdig > 6 )
     171           0 :             eScanType = SbxDOUBLE;
     172             : 
     173             :         // type detection?
     174           0 :         if( strchr( "%!&#", *p ) && *p ) p++;
     175             :     }
     176             :     // hex/octal number? read in and convert:
     177           0 :     else if( *p == '&' )
     178             :     {
     179           0 :         p++;
     180           0 :         eScanType = SbxLONG;
     181           0 :         const char *cmp = "0123456789ABCDEF";
     182           0 :         char base = 16;
     183           0 :         char ndig = 8;
     184           0 :         char xch  = *p++;
     185           0 :         switch( toupper( xch ) )
     186             :         {
     187           0 :             case 'O': cmp = "01234567"; base = 8; ndig = 11; break;
     188           0 :             case 'H': break;
     189           0 :             default : bRes = false;
     190             :         }
     191           0 :         long l = 0;
     192             :         int i;
     193           0 :         while( isalnum( *p ) )
     194             :         {
     195           0 :             char ch = sal::static_int_cast< char >( toupper( *p ) );
     196           0 :             p++;
     197           0 :             if( strchr( cmp, ch ) ) *q++ = ch;
     198           0 :             else bRes = false;
     199             :         }
     200           0 :         *q = 0;
     201           0 :         for( q = buf; *q; q++ )
     202             :         {
     203           0 :             i =( *q & 0xFF ) - '0';
     204           0 :             if( i > 9 ) i -= 7;
     205           0 :             l =( l * base ) + i;
     206           0 :             if( !ndig-- )
     207           0 :                 bRes = false;
     208             :         }
     209           0 :         if( *p == '&' ) p++;
     210           0 :         nVal = (double) l;
     211           0 :         if( l >= SbxMININT && l <= SbxMAXINT )
     212           0 :             eScanType = SbxINTEGER;
     213             :     }
     214             : #ifndef DISABLE_SCRIPTING
     215           0 :     else if ( SbiRuntime::isVBAEnabled() )
     216             :     {
     217             :         OSL_TRACE("Reporting error converting");
     218           0 :         return SbxERR_CONVERSION;
     219             :     }
     220             : #endif
     221           0 :     if( pLen )
     222           0 :         *pLen = (sal_uInt16) ( p - pStart );
     223           0 :     if( !bRes )
     224           0 :         return SbxERR_CONVERSION;
     225           0 :     if( bMinus )
     226           0 :         nVal = -nVal;
     227           0 :     rType = eScanType;
     228           0 :     return SbxERR_OK;
     229             : }
     230             : 
     231             : // port for CDbl in the Basic
     232           0 : SbxError SbxValue::ScanNumIntnl( const OUString& rSrc, double& nVal, bool bSingle )
     233             : {
     234             :     SbxDataType t;
     235           0 :     sal_uInt16 nLen = 0;
     236             :     SbxError nRetError = ImpScan( rSrc, nVal, t, &nLen,
     237           0 :         /*bAllowIntntl*/false, /*bOnlyIntntl*/true );
     238             :     // read completely?
     239           0 :     if( nRetError == SbxERR_OK && nLen != rSrc.getLength() )
     240             :     {
     241           0 :         nRetError = SbxERR_CONVERSION;
     242             :     }
     243           0 :     if( bSingle )
     244             :     {
     245           0 :         SbxValues aValues( nVal );
     246           0 :         nVal = (double)ImpGetSingle( &aValues );    // here error at overflow
     247             :     }
     248           0 :     return nRetError;
     249             : }
     250             : 
     251             : 
     252             : static double roundArray[] = {
     253             :     5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6, 0.5e-7,
     254             :     0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,0.5e-15 };
     255             : 
     256             : /***************************************************************************
     257             : |*
     258             : |*  void myftoa( double, char *, short, short, bool, bool )
     259             : |*
     260             : |*  description:        conversion double --> ASCII
     261             : |*  parameters:         double              the number
     262             : |*                      char *              target buffer
     263             : |*                      short               number of positions after decimal point
     264             : |*                      short               range of the exponent ( 0=no E )
     265             : |*                      bool                true: with 1000-separators
     266             : |*                      bool                true: output without formatting
     267             : |*
     268             : ***************************************************************************/
     269             : 
     270           4 : static void myftoa( double nNum, char * pBuf, short nPrec, short nExpWidth,
     271             :                     bool bPt, bool bFix, sal_Unicode cForceThousandSep = 0 )
     272             : {
     273             : 
     274           4 :     short nExp = 0;
     275           4 :     short nDig = nPrec + 1;
     276             :     short nDec;                         // number of positions before decimal point
     277             :     register int i;
     278             : 
     279             :     sal_Unicode cDecimalSep, cThousandSep;
     280           4 :     ImpGetIntntlSep( cDecimalSep, cThousandSep );
     281           4 :     if( cForceThousandSep )
     282           4 :         cThousandSep = cForceThousandSep;
     283             : 
     284             :     // compute exponent
     285           4 :     nExp = 0;
     286           4 :     if( nNum > 0.0 )
     287             :     {
     288           2 :         while( nNum <   1.0 ) nNum *= 10.0, nExp--;
     289           2 :         while( nNum >= 10.0 ) nNum /= 10.0, nExp++;
     290             :     }
     291           4 :     if( !bFix && !nExpWidth )
     292           0 :         nDig = nDig + nExp;
     293           4 :     else if( bFix && !nPrec )
     294           4 :         nDig = nExp + 1;
     295             : 
     296             :     // round number
     297           4 :     if( (nNum += roundArray [( nDig > 16 ) ? 16 : nDig] ) >= 10.0 )
     298             :     {
     299           0 :         nNum = 1.0;
     300           0 :         ++nExp;
     301           0 :         if( !nExpWidth ) ++nDig;
     302             :     }
     303             : 
     304             :     // determine positions before decimal point
     305           4 :     if( !nExpWidth )
     306             :     {
     307           4 :         if( nExp < 0 )
     308             :         {
     309             :             // #41691: also a 0 at bFix
     310           0 :             *pBuf++ = '0';
     311           0 :             if( nPrec ) *pBuf++ = (char)cDecimalSep;
     312           0 :             i = -nExp - 1;
     313           0 :             if( nDig <= 0 ) i = nPrec;
     314           0 :             while( i-- )    *pBuf++ = '0';
     315           0 :             nDec = 0;
     316             :         }
     317             :         else
     318           4 :             nDec = nExp+1;
     319             :     }
     320             :     else
     321           0 :         nDec = 1;
     322             : 
     323             :     // output number
     324           4 :     if( nDig > 0 )
     325             :     {
     326             :         register int digit;
     327           6 :         for( i = 0 ; ; ++i )
     328             :         {
     329           6 :             if( i < 16 )
     330             :             {
     331           6 :                 digit = (int) nNum;
     332           6 :                 *pBuf++ = sal::static_int_cast< char >(digit + '0');
     333           6 :                 nNum =( nNum - digit ) * 10.0;
     334             :             } else
     335           0 :                 *pBuf++ = '0';
     336           6 :             if( --nDig == 0 ) break;
     337           2 :             if( nDec )
     338             :             {
     339           2 :                 nDec--;
     340           2 :                 if( !nDec )
     341           0 :                     *pBuf++ = (char)cDecimalSep;
     342           2 :                 else if( !(nDec % 3 ) && bPt )
     343           0 :                     *pBuf++ = (char)cThousandSep;
     344             :             }
     345             :         }
     346             :     }
     347             : 
     348             :     // output exponent
     349           4 :     if( nExpWidth )
     350             :     {
     351           0 :         if( nExpWidth < 3 ) nExpWidth = 3;
     352           0 :         nExpWidth -= 2;
     353           0 :         *pBuf++ = 'E';
     354           0 :         *pBuf++ =( nExp < 0 ) ?( (nExp = -nExp ), '-' ) : '+';
     355           0 :         while( nExpWidth > 3 ) *pBuf++ = '0', nExpWidth--;
     356           0 :         if( nExp >= 100 || nExpWidth == 3 )
     357             :         {
     358           0 :             *pBuf++ = sal::static_int_cast< char >(nExp/100 + '0');
     359           0 :             nExp %= 100;
     360             :         }
     361           0 :         if( nExp/10 || nExpWidth >= 2 )
     362           0 :             *pBuf++ = sal::static_int_cast< char >(nExp/10 + '0');
     363           0 :         *pBuf++ = sal::static_int_cast< char >(nExp%10 + '0');
     364             :     }
     365           4 :     *pBuf = 0;
     366           4 : }
     367             : 
     368             : // The number is prepared unformattedly with the given number of
     369             : // NK-positions. A leading minus is added if applicable.
     370             : // This routine is public because it's also used by the Put-functions
     371             : // in the class SbxImpSTRING.
     372             : 
     373             : #ifdef _MSC_VER
     374             : #pragma optimize( "", off )
     375             : #pragma warning(disable: 4748) // "... because optimizations are disabled ..."
     376             : #endif
     377             : 
     378           4 : void ImpCvtNum( double nNum, short nPrec, ::rtl::OUString& rRes, bool bCoreString )
     379             : {
     380             :     char *q;
     381           4 :     char cBuf[ 40 ], *p = cBuf;
     382             : 
     383             :     sal_Unicode cDecimalSep, cThousandSep;
     384           4 :     ImpGetIntntlSep( cDecimalSep, cThousandSep );
     385           4 :     if( bCoreString )
     386           0 :         cDecimalSep = '.';
     387             : 
     388           4 :     if( nNum < 0.0 ) {
     389           0 :         nNum = -nNum;
     390           0 :         *p++ = '-';
     391             :     }
     392           4 :     double dMaxNumWithoutExp = (nPrec == 6) ? 1E6 : 1E14;
     393             :     myftoa( nNum, p, nPrec,( nNum &&( nNum < 1E-1 || nNum >= dMaxNumWithoutExp ) ) ? 4:0,
     394           4 :         false, true, cDecimalSep );
     395             :     // remove trailing zeros
     396           4 :     for( p = cBuf; *p &&( *p != 'E' ); p++ ) {}
     397           4 :     q = p; p--;
     398           4 :     while( nPrec && *p == '0' ) nPrec--, p--;
     399           4 :     if( *p == cDecimalSep ) p--;
     400           4 :     while( *q ) *++p = *q++;
     401           4 :     *++p = 0;
     402           4 :     rRes = ::rtl::OUString::createFromAscii( cBuf );
     403           4 : }
     404             : 
     405             : #ifdef _MSC_VER
     406             : #pragma optimize( "", on )
     407             : #endif
     408             : 
     409           0 : bool ImpConvStringExt( ::rtl::OUString& rSrc, SbxDataType eTargetType )
     410             : {
     411           0 :     bool bChanged = false;
     412           0 :     ::rtl::OUString aNewString;
     413             : 
     414             :     // only special cases are handled, nothing on default
     415           0 :     switch( eTargetType )
     416             :     {
     417             :         // consider international for floating point
     418             :         case SbxSINGLE:
     419             :         case SbxDOUBLE:
     420             :         case SbxCURRENCY:
     421             :         {
     422           0 :             ::rtl::OString aBStr( ::rtl::OUStringToOString( rSrc, RTL_TEXTENCODING_ASCII_US ) );
     423             : 
     424             :             sal_Unicode cDecimalSep, cThousandSep;
     425           0 :             ImpGetIntntlSep( cDecimalSep, cThousandSep );
     426           0 :             aNewString = rSrc;
     427             : 
     428           0 :             if( cDecimalSep != (sal_Unicode)'.' )
     429             :             {
     430           0 :                 sal_Int32 nPos = aNewString.indexOf( cDecimalSep );
     431           0 :                 if( nPos != -1 )
     432             :                 {
     433           0 :                     sal_Unicode* pStr = (sal_Unicode*)aNewString.getStr();
     434           0 :                     pStr[nPos] = (sal_Unicode)'.';
     435           0 :                     bChanged = true;
     436             :                 }
     437             :             }
     438           0 :             break;
     439             :         }
     440             : 
     441             :         // check as string in case of sal_Bool sal_True and sal_False
     442             :         case SbxBOOL:
     443             :         {
     444           0 :             if( rSrc.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("true")) )
     445             :             {
     446           0 :                 aNewString = ::rtl::OUString::valueOf( (sal_Int32)SbxTRUE );
     447           0 :                 bChanged = true;
     448             :             }
     449             :             else
     450           0 :             if( rSrc.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("false")) )
     451             :             {
     452           0 :                 aNewString = ::rtl::OUString::valueOf( (sal_Int32)SbxFALSE );
     453           0 :                 bChanged = true;
     454             :             }
     455           0 :             break;
     456             :         }
     457           0 :         default: break;
     458             :     }
     459             : 
     460           0 :     if( bChanged )
     461           0 :         rSrc = aNewString;
     462           0 :     return bChanged;
     463             : }
     464             : 
     465             : 
     466             : // formatted number output
     467             : // the return value is the number of characters used
     468             : // from the format
     469             : 
     470             : #ifdef _old_format_code_
     471             : // leave the code provisionally to copy the previous implementation
     472             : 
     473             : static sal_uInt16 printfmtnum( double nNum, OUString& rRes, const OUString& rWFmt )
     474             : {
     475             :     const String& rFmt = rWFmt;
     476             :     char    cFill  = ' ';           // filling characters
     477             :     char    cPre   = 0;             // start character ( maybe "$" )
     478             :     short   nExpDig= 0;             // number of exponent positions
     479             :     short   nPrec  = 0;             // number of positions after decimal point
     480             :     short   nWidth = 0;             // number range completely
     481             :     short   nLen;                   // length of converted number
     482             :     bool    bPoint = false;         // true: with 1000 seperators
     483             :     bool    bTrail = false;         // true, if following minus
     484             :     bool    bSign  = false;         // true: always with leading sign
     485             :     bool    bNeg   = false;         // true: number is negative
     486             :     char    cBuf [1024];            // number buffer
     487             :     char  * p;
     488             :     const char* pFmt = rFmt;
     489             :     rRes.Erase();
     490             :     // catch $$ and **, is simply output as character
     491             :     if( *pFmt == '$' )
     492             :       if( *++pFmt != '$' ) rRes += '$';
     493             :     if( *pFmt == '*' )
     494             :       if( *++pFmt != '*' ) rRes += '*';
     495             : 
     496             :     switch( *pFmt++ )
     497             :     {
     498             :         case 0:
     499             :             break;
     500             :         case '+':
     501             :             bSign = true; nWidth++; break;
     502             :         case '*':
     503             :             nWidth++; cFill = '*';
     504             :             if( *pFmt == '$' ) nWidth++, pFmt++, cPre = '$';
     505             :             break;
     506             :         case '$':
     507             :             nWidth++; cPre = '$'; break;
     508             :         case '#':
     509             :         case '.':
     510             :         case ',':
     511             :             pFmt--; break;
     512             :     }
     513             :     // pre point
     514             :     for( ;; )
     515             :     {
     516             :         while( *pFmt == '#' ) pFmt++, nWidth++;
     517             :         // 1000 separators?
     518             :         if( *pFmt == ',' )
     519             :         {
     520             :             nWidth++; pFmt++; bPoint = true;
     521             :         } else break;
     522             :     }
     523             :     // after point
     524             :     if( *pFmt == '.' )
     525             :     {
     526             :         while( *++pFmt == '#' ) nPrec++;
     527             :         nWidth += nPrec + 1;
     528             :     }
     529             :     // exponent
     530             :     while( *pFmt == '^' )
     531             :         pFmt++, nExpDig++, nWidth++;
     532             :     // following minus
     533             :     if( !bSign && *pFmt == '-' )
     534             :         pFmt++, bTrail = true;
     535             : 
     536             :     // convert number
     537             :     if( nPrec > 15 ) nPrec = 15;
     538             :     if( nNum < 0.0 ) nNum = -nNum, bNeg = true;
     539             :     p = cBuf;
     540             :     if( bSign ) *p++ = bNeg ? '-' : '+';
     541             :     myftoa( nNum, p, nPrec, nExpDig, bPoint, false );
     542             :     nLen = strlen( cBuf );
     543             : 
     544             :     // overflow?
     545             :     if( cPre ) nLen++;
     546             :     if( nLen > nWidth ) rRes += '%';
     547             :     else {
     548             :         nWidth -= nLen;
     549             :         while( nWidth-- ) rRes += (sal_Unicode)cFill;
     550             :         if( cPre ) rRes += (sal_Unicode)cPre;
     551             :     }
     552             :     rRes += (sal_Unicode*)&(cBuf[0]);
     553             :     if( bTrail )
     554             :         rRes += bNeg ? '-' : ' ';
     555             : 
     556             :     return (sal_uInt16) ( pFmt - (const char*) rFmt );
     557             : }
     558             : 
     559             : #endif //_old_format_code_
     560             : 
     561           0 : static sal_uInt16 printfmtstr( const OUString& rStr, OUString& rRes, const OUString& rFmt )
     562             : {
     563           0 :     OUStringBuffer aTemp;
     564           0 :     const sal_Unicode* pStr = rStr.getStr();
     565           0 :     const sal_Unicode* pFmtStart = rFmt.getStr();
     566           0 :     const sal_Unicode* pFmt = pFmtStart;
     567             : 
     568           0 :     switch( *pFmt )
     569             :     {
     570             :     case '!':
     571           0 :         aTemp.append(*pStr++);
     572           0 :         pFmt++;
     573           0 :         break;
     574             :     case '\\':
     575           0 :         do
     576             :         {
     577           0 :             aTemp.append( *pStr ? *pStr++ : static_cast< sal_Unicode >(' '));
     578           0 :             pFmt++;
     579             :         }
     580             :         while( *pFmt != '\\' );
     581           0 :         aTemp.append(*pStr ? *pStr++ : static_cast< sal_Unicode >(' '));
     582           0 :         pFmt++; break;
     583             :     case '&':
     584           0 :         aTemp = rStr;
     585           0 :         pFmt++; break;
     586             :     default:
     587           0 :         aTemp = rStr;
     588           0 :         break;
     589             :     }
     590           0 :     rRes = aTemp.makeStringAndClear();
     591           0 :     return (sal_uInt16) ( pFmt - pFmtStart );
     592             : }
     593             : 
     594             : 
     595           0 : sal_Bool SbxValue::Scan( const OUString& rSrc, sal_uInt16* pLen )
     596             : {
     597           0 :     SbxError eRes = SbxERR_OK;
     598           0 :     if( !CanWrite() )
     599             :     {
     600           0 :         eRes = SbxERR_PROP_READONLY;
     601             :     }
     602             :     else
     603             :     {
     604             :         double n;
     605             :         SbxDataType t;
     606           0 :         eRes = ImpScan( rSrc, n, t, pLen );
     607           0 :         if( eRes == SbxERR_OK )
     608             :         {
     609           0 :             if( !IsFixed() )
     610             :             {
     611           0 :                 SetType( t );
     612             :             }
     613           0 :             PutDouble( n );
     614             :         }
     615             :     }
     616           0 :     if( eRes )
     617             :     {
     618           0 :         SetError( eRes ); return sal_False;
     619             :     }
     620             :     else
     621             :     {
     622           0 :         return sal_True;
     623             :     }
     624             : }
     625             : 
     626             : 
     627           0 : ResMgr* implGetResMgr( void )
     628             : {
     629             :     static ResMgr* pResMgr = NULL;
     630           0 :     if( !pResMgr )
     631             :     {
     632           0 :         ::com::sun::star::lang::Locale aLocale = Application::GetSettings().GetUILanguageTag().getLocale();
     633           0 :         pResMgr = ResMgr::CreateResMgr("sb", aLocale );
     634             :     }
     635           0 :     return pResMgr;
     636             : }
     637             : 
     638             : class SbxValueFormatResId : public ResId
     639             : {
     640             : public:
     641           0 :     SbxValueFormatResId( sal_uInt16 nId )
     642           0 :         : ResId( nId, *implGetResMgr() )
     643           0 :     {}
     644             : };
     645             : 
     646             : 
     647             : enum VbaFormatType
     648             : {
     649             :     VBA_FORMAT_TYPE_OFFSET, // standard number format
     650             :     VBA_FORMAT_TYPE_USERDEFINED, // user defined number format
     651             :     VBA_FORMAT_TYPE_NULL
     652             : };
     653             : 
     654             : struct VbaFormatInfo
     655             : {
     656             :     VbaFormatType meType;
     657             :     const char* mpVbaFormat; // Format string in vba
     658             :     NfIndexTableOffset meOffset; // SvNumberFormatter format index, if meType = VBA_FORMAT_TYPE_OFFSET
     659             :     const char* mpOOoFormat; // if meType = VBA_FORMAT_TYPE_USERDEFINED
     660             : };
     661             : 
     662             : #define VBA_FORMAT_OFFSET( pcUtf8, eOffset ) \
     663             :     { VBA_FORMAT_TYPE_OFFSET, pcUtf8, eOffset, 0 }
     664             : 
     665             : #define VBA_FORMAT_USERDEFINED( pcUtf8, pcDefinedUtf8 ) \
     666             :     { VBA_FORMAT_TYPE_USERDEFINED, pcUtf8, NF_NUMBER_STANDARD, pcDefinedUtf8 }
     667             : 
     668             : static VbaFormatInfo pFormatInfoTable[] =
     669             : {
     670             :     VBA_FORMAT_OFFSET( "Long Date", NF_DATE_SYSTEM_LONG ),
     671             :     VBA_FORMAT_USERDEFINED( "Medium Date", "DD-MMM-YY" ),
     672             :     VBA_FORMAT_OFFSET( "Short Date", NF_DATE_SYSTEM_SHORT ),
     673             :     VBA_FORMAT_USERDEFINED( "Long Time", "H:MM:SS AM/PM" ),
     674             :     VBA_FORMAT_OFFSET( "Medium Time", NF_TIME_HHMMAMPM ),
     675             :     VBA_FORMAT_OFFSET( "Short Time", NF_TIME_HHMM ),
     676             :     VBA_FORMAT_OFFSET( "ddddd", NF_DATE_SYSTEM_SHORT ),
     677             :     VBA_FORMAT_OFFSET( "dddddd", NF_DATE_SYSTEM_LONG ),
     678             :     VBA_FORMAT_USERDEFINED( "ttttt", "H:MM:SS AM/PM" ),
     679             :     VBA_FORMAT_OFFSET( "ww", NF_DATE_WW ),
     680             :     { VBA_FORMAT_TYPE_NULL, 0, NF_INDEX_TABLE_ENTRIES, 0 }
     681             : };
     682             : 
     683           0 : VbaFormatInfo* getFormatInfo( const String& rFmt )
     684             : {
     685           0 :     VbaFormatInfo* pInfo = NULL;
     686           0 :     sal_Int16 i = 0;
     687           0 :     while( (pInfo = pFormatInfoTable + i )->mpVbaFormat != NULL )
     688             :     {
     689           0 :         if( rFmt.EqualsIgnoreCaseAscii( pInfo->mpVbaFormat ) )
     690           0 :             break;
     691           0 :         i++;
     692             :     }
     693           0 :     return pInfo;
     694             : }
     695             : 
     696             : #define VBAFORMAT_GENERALDATE       "General Date"
     697             : #define VBAFORMAT_C                 "c"
     698             : #define VBAFORMAT_N                 "n"
     699             : #define VBAFORMAT_NN                "nn"
     700             : #define VBAFORMAT_W                 "w"
     701             : #define VBAFORMAT_Y                 "y"
     702             : #define VBAFORMAT_LOWERCASE         "<"
     703             : #define VBAFORMAT_UPPERCASE         ">"
     704             : 
     705           0 : void SbxValue::Format( OUString& rRes, const OUString* pFmt ) const
     706             : {
     707           0 :     short nComma = 0;
     708           0 :     double d = 0;
     709             : 
     710             :     // pflin, It is better to use SvNumberFormatter to handle the date/time/number format.
     711             :     // the SvNumberFormatter output is mostly compatible with
     712             :     // VBA output besides the OOo-basic output
     713           0 :     if( pFmt && !SbxBasicFormater::isBasicFormat( *pFmt ) )
     714             :     {
     715           0 :         OUString aStr = GetOUString();
     716             : 
     717           0 :         if( pFmt->equalsIgnoreAsciiCase( VBAFORMAT_LOWERCASE ) )
     718             :         {
     719           0 :             rRes = aStr.toAsciiLowerCase();
     720             :             return;
     721             :         }
     722           0 :         if( pFmt->equalsIgnoreAsciiCase( VBAFORMAT_UPPERCASE ) )
     723             :         {
     724           0 :             rRes = aStr.toAsciiUpperCase();
     725             :             return;
     726             :         }
     727             : 
     728           0 :         LanguageType eLangType = GetpApp()->GetSettings().GetLanguageTag().getLanguageType();
     729             :         com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >
     730           0 :             xFactory = comphelper::getProcessServiceFactory();
     731           0 :         SvNumberFormatter aFormatter( xFactory, eLangType );
     732             : 
     733             :         sal_uInt32 nIndex;
     734             :         double nNumber;
     735             :         Color* pCol;
     736             : 
     737           0 :         sal_Bool bSuccess = aFormatter.IsNumberFormat( aStr, nIndex, nNumber );
     738             : 
     739             :         // number format, use SvNumberFormatter to handle it.
     740           0 :         if( bSuccess )
     741             :         {
     742           0 :             sal_Int32 nCheckPos = 0;
     743             :             short nType;
     744           0 :             OUString aFmtStr = *pFmt;
     745           0 :             VbaFormatInfo* pInfo = getFormatInfo( aFmtStr );
     746           0 :             if( pInfo && pInfo->meType != VBA_FORMAT_TYPE_NULL )
     747             :             {
     748           0 :                 if( pInfo->meType == VBA_FORMAT_TYPE_OFFSET )
     749             :                 {
     750           0 :                     nIndex = aFormatter.GetFormatIndex( pInfo->meOffset, eLangType );
     751             :                 }
     752             :                 else
     753             :                 {
     754           0 :                     aFmtStr = rtl::OUString::createFromAscii(pInfo->mpOOoFormat);
     755           0 :                     aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType );
     756             :                 }
     757           0 :                 aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol );
     758             :             }
     759           0 :             else if( aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_GENERALDATE )
     760           0 :                     || aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_C ))
     761             :             {
     762           0 :                 if( nNumber <=-1.0 || nNumber >= 1.0 )
     763             :                 {
     764             :                     // short date
     765           0 :                     nIndex = aFormatter.GetFormatIndex( NF_DATE_SYSTEM_SHORT, eLangType );
     766           0 :                     aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol );
     767             : 
     768             :                     // long time
     769           0 :                     if( floor( nNumber ) != nNumber )
     770             :                     {
     771           0 :                         aFmtStr = "H:MM:SS AM/PM";
     772           0 :                         aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType );
     773           0 :                         OUString aTime;
     774           0 :                         aFormatter.GetOutputString( nNumber, nIndex, aTime, &pCol );
     775           0 :                         rRes += " ";
     776           0 :                         rRes += aTime;
     777           0 :                     }
     778             :                 }
     779             :                 else
     780             :                 {
     781             :                     // long time only
     782           0 :                     aFmtStr = "H:MM:SS AM/PM";
     783           0 :                     aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType );
     784           0 :                     aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol );
     785             :                 }
     786             :             }
     787           0 :             else if( aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_N ) ||
     788           0 :                      aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_NN ))
     789             :             {
     790           0 :                 sal_Int32 nMin = implGetMinute( nNumber );
     791           0 :                 if( nMin < 10 && aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_NN ))
     792             :                 {
     793             :                     // Minute in two digits
     794             :                      sal_Unicode aBuf[2];
     795           0 :                      aBuf[0] = '0';
     796           0 :                      aBuf[1] = '0' + nMin;
     797           0 :                      rRes = OUString(aBuf, SAL_N_ELEMENTS(aBuf));
     798             :                 }
     799             :                 else
     800             :                 {
     801           0 :                     rRes = rtl::OUString::valueOf(nMin);
     802             :                 }
     803             :             }
     804           0 :             else if( aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_W ))
     805             :             {
     806           0 :                 sal_Int32 nWeekDay = implGetWeekDay( nNumber );
     807           0 :                 rRes = rtl::OUString::valueOf(nWeekDay);
     808             :             }
     809           0 :             else if( aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_Y ))
     810             :             {
     811           0 :                 sal_Int16 nYear = implGetDateYear( nNumber );
     812             :                 double dBaseDate;
     813           0 :                 implDateSerial( nYear, 1, 1, dBaseDate );
     814           0 :                 sal_Int32 nYear32 = 1 + sal_Int32( nNumber - dBaseDate );
     815           0 :                 rRes = rtl::OUString::valueOf(nYear32);
     816             :             }
     817             :             else
     818             :             {
     819           0 :                 aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType );
     820           0 :                 aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol );
     821             :             }
     822             : 
     823           0 :             return;
     824           0 :         }
     825             :     }
     826             : 
     827           0 :     SbxDataType eType = GetType();
     828           0 :     switch( eType )
     829             :     {
     830             :     case SbxCHAR:
     831             :     case SbxBYTE:
     832             :     case SbxINTEGER:
     833             :     case SbxUSHORT:
     834             :     case SbxLONG:
     835             :     case SbxULONG:
     836             :     case SbxINT:
     837             :     case SbxUINT:
     838             :     case SbxNULL:       // #45929 NULL with a little cheating
     839           0 :         nComma = 0;     goto cvt;
     840             :     case SbxSINGLE:
     841           0 :         nComma = 6;     goto cvt;
     842             :     case SbxDOUBLE:
     843           0 :         nComma = 14;
     844             : 
     845             :     cvt:
     846           0 :         if( eType != SbxNULL )
     847             :         {
     848           0 :             d = GetDouble();
     849             :         }
     850             :         // #45355 another point to jump in for isnumeric-String
     851             :     cvt2:
     852           0 :         if( pFmt )
     853             :         {
     854           0 :             SbxAppData& rAppData = GetSbxData_Impl();
     855             : 
     856           0 :             LanguageType eLangType = GetpApp()->GetSettings().GetLanguageTag().getLanguageType();
     857           0 :             if( rAppData.pBasicFormater )
     858             :             {
     859           0 :                 if( rAppData.eBasicFormaterLangType != eLangType )
     860             :                 {
     861           0 :                     delete rAppData.pBasicFormater;
     862           0 :                     rAppData.pBasicFormater = NULL;
     863             :                 }
     864             :             }
     865           0 :             rAppData.eBasicFormaterLangType = eLangType;
     866             : 
     867             : 
     868           0 :             if( !rAppData.pBasicFormater )
     869             :             {
     870           0 :                 SvtSysLocale aSysLocale;
     871           0 :                 const LocaleDataWrapper& rData = aSysLocale.GetLocaleData();
     872           0 :                 sal_Unicode cComma = rData.getNumDecimalSep()[0];
     873           0 :                 sal_Unicode c1000  = rData.getNumThousandSep()[0];
     874           0 :                 OUString aCurrencyStrg = rData.getCurrSymbol();
     875             : 
     876             :                 // initialize the Basic-formater help object:
     877             :                 // get resources for predefined output
     878             :                 // of the Format()-command, e. g. for "On/Off"
     879           0 :                 OUString aOnStrg = SbxValueFormatResId(STR_BASICKEY_FORMAT_ON).toString();
     880           0 :                 OUString aOffStrg = SbxValueFormatResId(STR_BASICKEY_FORMAT_OFF).toString();
     881           0 :                 OUString aYesStrg = SbxValueFormatResId(STR_BASICKEY_FORMAT_YES).toString();
     882           0 :                 OUString aNoStrg = SbxValueFormatResId(STR_BASICKEY_FORMAT_NO).toString();
     883           0 :                 OUString aTrueStrg = SbxValueFormatResId(STR_BASICKEY_FORMAT_TRUE).toString();
     884           0 :                 OUString aFalseStrg = SbxValueFormatResId(STR_BASICKEY_FORMAT_FALSE).toString();
     885           0 :                 OUString aCurrencyFormatStrg = SbxValueFormatResId(STR_BASICKEY_FORMAT_CURRENCY).toString();
     886             : 
     887             :                 rAppData.pBasicFormater = new SbxBasicFormater( cComma,c1000,aOnStrg,aOffStrg,
     888             :                                                                 aYesStrg,aNoStrg,aTrueStrg,aFalseStrg,
     889           0 :                                                                 aCurrencyStrg,aCurrencyFormatStrg );
     890             :             }
     891             :             // Remark: For performance reasons there's only ONE BasicFormater-
     892             :             //    object created and 'stored', so that the expensive resource-
     893             :             //    loading is saved (for country-specific predefined outputs,
     894             :             //    e. g. "On/Off") and the continous string-creation
     895             :             //    operations, too.
     896             :             // BUT: therefore this code is NOT multithreading capable!
     897             : 
     898             :             // here are problems with ;;;Null because this method is only
     899             :             // called, if SbxValue is a number!!!
     900             :             // in addition rAppData.pBasicFormater->BasicFormatNull( *pFmt ); could be called!
     901           0 :             if( eType != SbxNULL )
     902             :             {
     903           0 :                 rRes = rAppData.pBasicFormater->BasicFormat( d ,*pFmt );
     904             :             }
     905             :             else
     906             :             {
     907           0 :                 rRes = rAppData.pBasicFormater->BasicFormatNull( *pFmt );
     908             :             }
     909             : 
     910             :         }
     911             :         else
     912             :         {
     913           0 :             OUString aTmpString( rRes );
     914           0 :             ImpCvtNum( GetDouble(), nComma, aTmpString );
     915           0 :             rRes = aTmpString;
     916             :         }
     917           0 :         break;
     918             :     case SbxSTRING:
     919           0 :         if( pFmt )
     920             :         {
     921             :             // #45355 converting if numeric
     922           0 :             if( IsNumericRTL() )
     923             :             {
     924           0 :                 ScanNumIntnl( GetOUString(), d, /*bSingle*/false );
     925           0 :                 goto cvt2;
     926             :             }
     927             :             else
     928             :             {
     929           0 :                 printfmtstr( GetOUString(), rRes, *pFmt );
     930             :             }
     931             :         }
     932             :         else
     933             :         {
     934           0 :             rRes = GetOUString();
     935             :         }
     936           0 :         break;
     937             :     default:
     938           0 :         rRes = GetOUString();
     939             :     }
     940             : }
     941             : 
     942             : 
     943             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10