lvyue schrieb:
Hi, Daniel
Thanks for your reply, and sorry I did not reply on time,
there is something wrong with my mail box.

and I have attached a diff in issue 93789,
http://www.openoffice.org/issues/show_bug.cgi?id=93789
can you check it and tell me where is wrong?

Found the problem... See below. I have some more comments regarding the patch:


1)

+BOOL lclConvertMoney( const String aSearchUnit, double& rfRate, int& rnDec )
+{
+#define COUNT 16
+#define CURRENCY( name ) \
+    (String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( name ) ))
+    ConvertInfo aConvertTable[ COUNT ] = {
+        { CURRENCY( "EUR" ), 1.0,      2 },


I am not sure (->Eike?) but initializing the strings this way may fail with certain compilers.

Please do not #define the COUNT but calculate the array size after the array. In the future, more countries may convert to the Euro currency. This may be the source of errors when the next developer forgets to update the COUNT after adding a line to the list. Better:

const ConvertInfo aConvertTable[] = {
 ...
};

const int COUNT = sizeof( aConvertTable ) / sizeof( ConvertInfo );

This is the byte-size of the entire table, divided by the byte-size of one entry, therefore always the number of entries.



2)

But now for the interesting part:

+
+                        case xlExtEuroConvert:
+                            {
+ aStack << aPool.Store( ocEuroConvert, pExtName->GetName() );
+                            }
+                        break;

Here, you push the ocEuroConvert op-code together with the function name pExtName->GetName(). This will be converted by the filter to a token containing op-code and string. The interpreter finds the token with ocEuroConvert, gets its function name "EUROCONVERT" from the resources. Then it finds an additional string "EUROCONVERT" in the token, and appends it to the already existing function name. EUROCONVERT is an internal name, therefore the function name must not be part of the token. This is only needed for the ocExternal add-in functions. I see... we need some more "dirty" hacking of the formula import code. First, change the line to

aStack << aPool.Store( ocEuroConvert, String() );

to pass an empty string. The code to convert the Excel tokens to Calc tokens is located in sc/source/filter/excel/tokstack.cxx. This code is more than old and has been the source of some issues regarding formula import :-( In line 371, you find a "case T_Ext:" which converts the token added with the "aPool.Store" call above to a Calc token. To not break anything else (hopefully), this has to be changed to (new lines marked with +):

    case T_Ext:
    {
        UINT16 n = pElement[ nId ];
        EXTCONT* p = ( n < nP_Ext )? ppP_Ext[ n ] : NULL;

        if( p )
+       {
+           if( p->eId == ocExternal )
+               pScToken->AddOpCode( p->eId );
+           else
                pScToken->AddExternal( p->aText, p->eId );
+       }
    }
    break;




3)

+ else if ( maName == String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("EUROCONVERT") ) )
+            meType = xlExtEuroConvert;

Better readable would be:

else if ( maName.EqualsIgnoreCaseAscii( "EUROCONVERT" ) )

Attention: The name "EUROCONVERT" may be used in other external names than the EUROTOOL addin (example: a user does not have the EUROTOOL addin, and defines the named range "EUROCONVERT" in one of his documents and refers to it from another document). So the information that the name is part of the EUROTOOL.XLA addin has to be transported to the constructor of XclImpExtName. Please replace the "bool bAddIn" parameter by something else able to transport both information. For example, pass the enum XclSupbookType directly instead of a bool testing for the add-in type only:

else if ( (eType == EXC_SBTYPE_EUROTOOL) && maName.EqualsIgnoreCaseAscii( "EUROCONVERT" ) )



4)

+    if( String( maXclUrl.GetBuffer() + 1 )
+ == String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("EUROTOOL.XLA") ) )

In general, please use String::Copy() instead of String::GetBuffer(), it is more readable and faster. The String::Copy() function takes 0 to 2 parameters, if it gets 1, it copies and returns from the passed position to the end of the string. So, in this example, "maXclUrl.Copy( 1 )" would do the same as "String( maXclUrl.GetBuffer() + 1 )" *and* is save against empty strings. :-)

But, in our case, we should not ignore the first byte, there may be another external reference to the regular file "XEUROTOOL.XLA" which would trigger this comparison too. Better to use a case-insensitive comparison to the full name:

if( maXclUrl.EqualsIgnoreCaseAscii( "\008EUROTOOL.XLA" ) )

Note the characters \008 which encode the ASCII character 8.




Best regards
Daniel


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to