1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
24 #include <tools/debug.hxx>
25 #include <database.hxx>
26 #include <globals.hxx>
27 #include <rtl/strbuf.hxx>
28 #include <osl/file.hxx>
30 SvIdlDataBase::SvIdlDataBase( const SvCommand
& rCmd
)
33 , nVerbosity( rCmd
.nVerbosity
)
36 sSlotMapFile
= rCmd
.aSlotMapFile
;
39 SvIdlDataBase::~SvIdlDataBase()
46 #define ADD_TYPE( Name, OdlName, ParserChar, CName, BasName, BasPost ) \
47 aTypeList.push_back( new SvMetaType( SvHash_##Name()->GetName(), \
48 BasName, OdlName, ParserChar, CName, BasName, BasPost ) );
50 SvMetaTypeMemberList
& SvIdlDataBase::GetTypeList()
52 if( aTypeList
.empty() )
54 aTypeList
.push_back( new SvMetaTypeString() );
55 aTypeList
.push_back( new SvMetaTypevoid() );
57 // MI: IDispatch::Invoke can not unsigned
58 ADD_TYPE( UINT16
, "long", 'h', "unsigned short", "Long", "&" );
59 ADD_TYPE( INT16
, "short", 'h', "short", "Integer", "%" );
60 ADD_TYPE( UINT32
, "long", 'l', "unsigned long", "Long", "&" );
61 ADD_TYPE( INT32
, "long", 'l', "long", "Long", "&" );
62 ADD_TYPE( int, "int", 'i', "int", "Integer", "%" );
63 ADD_TYPE( BOOL
, "boolean", 'b', "unsigned char", "Boolean", "" );
64 ADD_TYPE( char, "char", 'c', "char", "Integer", "%" );
65 ADD_TYPE( BYTE
, "char", 'c', "unsigned char", "Integer", "%" );
66 ADD_TYPE( float, "float", 'f', "float", "Single", "!" );
67 ADD_TYPE( double, "double", 'F', "double", "Double", "#" );
68 ADD_TYPE( SbxObject
, "VARIANT", 'o', "C_Object", "Object", "" );
70 // Attention! When adding types all binary data bases get incompatible
76 SvMetaModule
* SvIdlDataBase::GetModule( const OString
& rName
)
78 for( sal_uLong n
= 0; n
< aModuleList
.size(); n
++ )
79 if( aModuleList
[n
]->GetName().getString().equals(rName
) )
80 return aModuleList
[n
];
84 void SvIdlDataBase::SetError( const OString
& rError
, SvToken
* pTok
)
86 if( pTok
->GetLine() > 10000 )
87 aError
.SetText( "line count overflow" );
89 if( aError
.nLine
< pTok
->GetLine()
90 || (aError
.nLine
== pTok
->GetLine() && aError
.nColumn
< pTok
->GetColumn()) )
92 aError
= SvIdlError( pTok
->GetLine(), pTok
->GetColumn() );
93 aError
.SetText( rError
);
97 void SvIdlDataBase::Push( SvMetaObject
* pObj
)
99 GetStack().Push( pObj
);
102 bool SvIdlDataBase::FindId( const OString
& rIdName
, sal_uLong
* pVal
)
107 if( pIdTable
->Test( rIdName
, &nHash
) )
109 *pVal
= pIdTable
->Get( nHash
)->GetValue();
116 bool SvIdlDataBase::InsertId( const OString
& rIdName
, sal_uLong nVal
)
119 pIdTable
= new SvStringHashTable( 20003 );
122 if( pIdTable
->Insert( rIdName
, &nHash
) )
124 pIdTable
->Get( nHash
)->SetValue( nVal
);
130 bool SvIdlDataBase::ReadIdFile( const OUString
& rFileName
)
133 osl::File::searchFileURL( rFileName
, GetPath(), aFullName
);
134 osl::FileBase::getSystemPathFromFileURL( aFullName
, aFullName
);
136 for ( size_t i
= 0, n
= aIdFileList
.size(); i
< n
; ++i
)
137 if ( aIdFileList
[ i
] == rFileName
)
140 aIdFileList
.push_back( rFileName
);
141 this->AddDepFile( aFullName
);
142 SvTokenStream
aTokStm( aFullName
);
143 if( aTokStm
.GetStream().GetError() == SVSTREAM_OK
)
145 SvToken
* pTok
= aTokStm
.GetToken_Next();
147 while( !pTok
->IsEof() )
149 if( pTok
->IsChar() && pTok
->GetChar() == '#' )
151 pTok
= aTokStm
.GetToken_Next();
152 if( pTok
->Is( SvHash_define() ) )
154 pTok
= aTokStm
.GetToken_Next();
156 if( pTok
->IsIdentifier() )
157 aDefName
= pTok
->GetString();
160 OString
aStr("unexpected token after define");
162 SetError( aStr
, pTok
);
163 WriteError( aTokStm
);
171 pTok
= aTokStm
.GetToken_Next();
172 if( pTok
->IsIdentifier() )
175 if( FindId( pTok
->GetString(), &n
) )
180 else if( pTok
->IsChar() )
182 if( pTok
->GetChar() == '-'
183 || pTok
->GetChar() == '/'
184 || pTok
->GetChar() == '*'
185 || pTok
->GetChar() == '&'
186 || pTok
->GetChar() == '|'
187 || pTok
->GetChar() == '^'
188 || pTok
->GetChar() == '~' )
190 OStringBuffer
aStr("unknown operator '");
191 aStr
.append(pTok
->GetChar());
192 aStr
.append("'in define");
194 SetError( aStr
.makeStringAndClear(), pTok
);
195 WriteError( aTokStm
);
198 if( pTok
->GetChar() != '+'
199 && pTok
->GetChar() != '('
200 && pTok
->GetChar() != ')' )
201 // only + is allowed, parentheses are immaterial
202 // because + is commutative
205 else if( pTok
->IsInteger() )
207 nVal
+= pTok
->GetNumber();
214 if( !InsertId( aDefName
, nVal
) )
216 OString
aStr("hash table overflow: ");
217 SetError( aStr
, pTok
);
218 WriteError( aTokStm
);
223 else if( pTok
->Is( SvHash_include() ) )
225 pTok
= aTokStm
.GetToken_Next();
227 if( pTok
->IsString() )
228 aName
.append(pTok
->GetString());
229 else if( pTok
->IsChar() && pTok
->GetChar() == '<' )
231 pTok
= aTokStm
.GetToken_Next();
232 while( !pTok
->IsEof()
233 && !(pTok
->IsChar() && pTok
->GetChar() == '>') )
235 aName
.append(pTok
->GetTokenAsString());
236 pTok
= aTokStm
.GetToken_Next();
240 OString
aStr("unexpected eof in #include");
242 SetError(aStr
, pTok
);
243 WriteError( aTokStm
);
247 if (!ReadIdFile(OStringToOUString(aName
.toString(),
248 RTL_TEXTENCODING_ASCII_US
)))
250 OStringBuffer
aStr("cannot read file: ");
251 aStr
.append(aName
.makeStringAndClear());
252 SetError(aStr
.makeStringAndClear(), pTok
);
253 WriteError( aTokStm
);
259 pTok
= aTokStm
.GetToken_Next();
267 SvMetaType
* SvIdlDataBase::FindType( const SvMetaType
* pPType
,
268 SvMetaTypeMemberList
& rList
)
270 for( SvMetaTypeMemberList::const_iterator it
= rList
.begin(); it
!= rList
.end(); ++it
)
276 SvMetaType
* SvIdlDataBase::FindType( const OString
& rName
)
278 for( SvMetaTypeMemberList::const_iterator it
= aTypeList
.begin(); it
!= aTypeList
.end(); ++it
)
279 if( rName
.equals((*it
)->GetName().getString()) )
284 SvMetaType
* SvIdlDataBase::ReadKnownType( SvTokenStream
& rInStm
)
288 int nCall0
= CALL_VALUE
;
289 int nCall1
= CALL_VALUE
;
290 bool bSet
= false; // any attribute set
292 sal_uInt32 nTokPos
= rInStm
.Tell();
293 SvToken
* pTok
= rInStm
.GetToken_Next();
295 if( pTok
->HasHash() )
297 sal_uInt32 nBeginPos
= 0; // can not happen with Tell
298 while( nBeginPos
!= rInStm
.Tell() )
300 nBeginPos
= rInStm
.Tell();
301 if( pTok
->Is( SvHash_in() ) )
304 pTok
= rInStm
.GetToken_Next();
307 if( pTok
->Is( SvHash_out() ) )
310 pTok
= rInStm
.GetToken_Next();
313 if( pTok
->Is( SvHash_inout() ) )
317 pTok
= rInStm
.GetToken_Next();
323 if( pTok
->IsIdentifier() )
325 OString aName
= pTok
->GetString();
326 SvMetaTypeMemberList
& rList
= GetTypeList();
327 SvMetaTypeMemberList::const_iterator it
= rList
.begin();
328 SvMetaType
* pType
= NULL
;
329 while( it
!= rList
.end() )
331 if( (*it
)->GetName().getString().equals(aName
) )
340 pTok
= rInStm
.GetToken();
343 if( pTok
->GetChar() == '&' || pTok
->GetChar() == '*' )
345 nCall0
= (pTok
->GetChar() == '&') ? CALL_REFERENCE
:
347 rInStm
.GetToken_Next();
348 pTok
= rInStm
.GetToken();
349 if( pTok
->GetChar() == '&' || pTok
->GetChar() == '*' )
351 nCall1
= (pTok
->GetChar() == '&') ? CALL_REFERENCE
:
353 rInStm
.GetToken_Next();
360 // is exactly this type
363 DBG_ASSERT( aTmpTypeList
.front(), "mindestens ein Element" );
364 SvMetaTypeRef xType
= new SvMetaType( pType
->GetName().getString(), 'h', "dummy" );
365 xType
->SetRef( pType
);
367 xType
->SetOut( bOut
);
368 xType
->SetCall0( nCall0
);
369 xType
->SetCall1( nCall1
);
371 aTmpTypeList
.push_back( xType
);
375 rInStm
.Seek( nTokPos
);
379 SvMetaAttribute
* SvIdlDataBase::ReadKnownAttr
381 SvTokenStream
& rInStm
,
382 SvMetaType
* pType
/* If pType == NULL, then the type has
386 sal_uInt32 nTokPos
= rInStm
.Tell();
389 pType
= ReadKnownType( rInStm
);
394 SvToken
* pTok
= rInStm
.GetToken_Next();
395 if( pTok
->IsIdentifier() )
398 if( FindId( pTok
->GetString(), &n
) )
400 for( sal_uLong i
= 0; i
< aAttrList
.size(); i
++ )
402 SvMetaAttribute
* pAttr
= aAttrList
[i
];
403 if( pAttr
->GetSlotId().getString().equals(pTok
->GetString()) )
408 OStringBuffer
aStr("Nicht gefunden : ");
409 aStr
.append(pTok
->GetString());
410 OSL_FAIL(aStr
.getStr());
414 rInStm
.Seek( nTokPos
);
418 SvMetaAttribute
* SvIdlDataBase::SearchKnownAttr
420 const SvNumberIdentifier
& rId
424 if( FindId( rId
.getString(), &n
) )
426 for( sal_uLong i
= 0; i
< aAttrList
.size(); i
++ )
428 SvMetaAttribute
* pAttr
= aAttrList
[i
];
429 if( pAttr
->GetSlotId().getString() == rId
.getString() )
437 SvMetaClass
* SvIdlDataBase::ReadKnownClass( SvTokenStream
& rInStm
)
439 sal_uInt32 nTokPos
= rInStm
.Tell();
440 SvToken
* pTok
= rInStm
.GetToken_Next();
442 if( pTok
->IsIdentifier() )
443 for( sal_uLong n
= 0; n
< aClassList
.size(); n
++ )
445 SvMetaClass
* pClass
= aClassList
[n
];
446 if( pClass
->GetName().getString().equals(pTok
->GetString()) )
450 rInStm
.Seek( nTokPos
);
454 void SvIdlDataBase::Write(const OString
& rText
)
456 if( nVerbosity
!= 0 )
457 fprintf( stdout
, "%s", rText
.getStr() );
460 void SvIdlDataBase::WriteError( const OString
& rErrWrn
,
461 const OString
& rFileName
,
462 const OString
& rErrorText
,
463 sal_uLong nRow
, sal_uLong nColumn
)
466 fprintf( stderr
, "\n%s --- %s: ( %ld, %ld )\n",
467 rFileName
.getStr(), rErrWrn
.getStr(), nRow
, nColumn
);
469 if( !rErrorText
.isEmpty() )
471 fprintf( stderr
, "\t%s\n", rErrorText
.getStr() );
475 void SvIdlDataBase::WriteError( SvTokenStream
& rInStm
)
478 OUString
aFileName( rInStm
.GetFileName() );
479 OStringBuffer aErrorText
;
480 sal_uLong nRow
= 0, nColumn
= 0;
483 SvToken
*pTok
= rInStm
.GetToken();
486 nRow
= pTok
->GetLine();
487 nColumn
= pTok
->GetColumn();
489 if( aError
.IsError() )
491 // search error token
493 if( !aError
.GetText().isEmpty() )
495 aErrorText
.append("may be <");
496 aErrorText
.append(aError
.GetText());
498 SvToken
* pPrevTok
= NULL
;
499 while( pTok
!= pPrevTok
)
502 if( pTok
->GetLine() == aError
.nLine
503 && pTok
->GetColumn() == aError
.nColumn
)
505 pTok
= rInStm
.GetToken_PrevAll();
509 aErrorText
.append("> at ( ");
510 aErrorText
.append(static_cast<sal_Int64
>(aError
.nLine
));
511 aErrorText
.append(", ");
512 aErrorText
.append(static_cast<sal_Int64
>(aError
.nColumn
));
513 aErrorText
.append(" )");
516 aError
= SvIdlError();
519 WriteError("error", OUStringToOString(aFileName
,
520 RTL_TEXTENCODING_UTF8
), aErrorText
.makeStringAndClear(), nRow
, nColumn
);
522 DBG_ASSERT( pTok
, "token must be found" );
526 // look for identifier close by
527 if( !pTok
->IsIdentifier() )
529 rInStm
.GetToken_PrevAll();
530 pTok
= rInStm
.GetToken();
532 if( pTok
&& pTok
->IsIdentifier() )
534 OString aN
= IDLAPP
->pHashTable
->GetNearString( pTok
->GetString() );
536 fprintf( stderr
, "%s versus %s\n", pTok
->GetString().getStr(), aN
.getStr() );
540 SvIdlWorkingBase::SvIdlWorkingBase(const SvCommand
& rCmd
) : SvIdlDataBase(rCmd
)
544 bool SvIdlWorkingBase::ReadSvIdl( SvTokenStream
& rInStm
, bool bImported
, const OUString
& rPath
)
546 aPath
= rPath
; // only valid for this iteration
548 SvToken
* pTok
= rInStm
.GetToken();
549 // only one import at the very beginning
550 if( pTok
->Is( SvHash_import() ) )
552 rInStm
.GetToken_Next();
553 bOk
= rInStm
.Read( '(' ); // optional
554 pTok
= bOk
? rInStm
.GetToken_Next() : NULL
;
555 if( pTok
&& pTok
->IsString() )
558 if( osl::FileBase::E_None
== osl::File::searchFileURL(
559 OStringToOUString(pTok
->GetString(), RTL_TEXTENCODING_ASCII_US
),
563 osl::FileBase::getSystemPathFromFileURL( aFullName
, aFullName
);
564 this->AddDepFile(aFullName
);
565 SvFileStream
aStm( aFullName
, STREAM_STD_READ
| StreamMode::NOCREATE
);
566 SvTokenStream
aTokStm( aStm
, aFullName
);
567 bOk
= ReadSvIdl( aTokStm
, true, rPath
);
576 sal_uInt32 nBeginPos
= 0xFFFFFFFF; // can not happen with Tell
578 while( bOk
&& nBeginPos
!= rInStm
.Tell() )
580 nBeginPos
= rInStm
.Tell();
581 pTok
= rInStm
.GetToken();
584 if( pTok
->IsEmpty() )
587 // only one import at the very beginning
588 if( pTok
->Is( SvHash_module() ) )
590 SvMetaModuleRef aModule
= new SvMetaModule( rInStm
.GetFileName(), bImported
);
591 if( aModule
->ReadSvIdl( *this, rInStm
) )
592 GetModuleList().push_back( aModule
);
599 if( !bOk
|| !pTok
->IsEof() )
602 WriteError( rInStm
);
608 bool SvIdlWorkingBase::WriteSfx( SvStream
& rOutStm
)
610 if( rOutStm
.GetError() != SVSTREAM_OK
)
613 // reset all tmp variables for writing
615 SvMemoryStream
aTmpStm( 256000, 256000 );
617 for( n
= 0; n
< GetModuleList().size(); n
++ )
619 SvMetaModule
* pModule
= GetModuleList()[n
];
620 if( !pModule
->IsImported() )
621 pModule
->WriteSfx( *this, aTmpStm
);
624 for( n
= 0; n
< aUsedTypes
.size(); n
++ )
626 SvMetaType
* pType
= aUsedTypes
[n
];
627 pType
->WriteSfx( *this, rOutStm
);
630 rOutStm
.WriteStream( aTmpStm
);
634 void SvIdlDataBase::StartNewFile( const OUString
& rName
)
636 bExport
= ( aExportFile
.equalsIgnoreAsciiCase( rName
) );
639 void SvIdlDataBase::AppendAttr( SvMetaAttribute
*pAttr
)
641 aAttrList
.push_back( pAttr
);
643 pAttr
->SetNewAttribute( true );
646 void SvIdlDataBase::AddDepFile(OUString
const& rFileName
)
648 m_DepFiles
.insert(rFileName
);
653 SvFileStream
& m_rStream
;
654 explicit WriteDep(SvFileStream
& rStream
) : m_rStream(rStream
) { }
655 void operator() (OUString
const& rItem
)
657 m_rStream
.WriteCharPtr( " \\\n " );
658 m_rStream
.WriteCharPtr( OUStringToOString(rItem
, RTL_TEXTENCODING_UTF8
).getStr() );
662 // write a dummy target for one included file, so the incremental build does
663 // not break with "No rule to make target" if the included file is removed
666 SvFileStream
& m_rStream
;
667 explicit WriteDummy(SvFileStream
& rStream
) : m_rStream(rStream
) { }
668 void operator() (OUString
const& rItem
)
670 m_rStream
.WriteCharPtr( OUStringToOString(rItem
, RTL_TEXTENCODING_UTF8
).getStr() );
671 m_rStream
.WriteCharPtr( " :\n\n" );
675 bool SvIdlDataBase::WriteDepFile(
676 SvFileStream
& rStream
, OUString
const& rTarget
)
678 rStream
.WriteCharPtr( OUStringToOString(rTarget
, RTL_TEXTENCODING_UTF8
).getStr() );
679 rStream
.WriteCharPtr( " :" );
680 ::std::for_each(m_DepFiles
.begin(), m_DepFiles
.end(), WriteDep(rStream
));
681 rStream
.WriteCharPtr( "\n\n" );
682 ::std::for_each(m_DepFiles
.begin(), m_DepFiles
.end(), WriteDummy(rStream
));
683 return rStream
.GetError() == SVSTREAM_OK
;
686 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */