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 .
20 #include <sal/config.h>
24 #include <string_view>
26 #include <command.hxx>
27 #include <database.hxx>
28 #include <globals.hxx>
30 #include <rtl/strbuf.hxx>
31 #include <osl/file.hxx>
34 SvParseException::SvParseException( SvTokenStream
const & rInStm
, const OString
& rError
)
36 SvToken
& rTok
= rInStm
.GetToken();
37 aError
= SvIdlError( rTok
.GetLine(), rTok
.GetColumn() );
38 aError
.SetText( rError
);
41 SvParseException::SvParseException( const OString
& rError
, SvToken
const & rTok
)
43 aError
= SvIdlError( rTok
.GetLine(), rTok
.GetColumn() );
44 aError
.SetText( rError
);
48 SvIdlDataBase::SvIdlDataBase( const SvCommand
& rCmd
)
51 , nVerbosity( rCmd
.nVerbosity
)
53 sSlotMapFile
= rCmd
.aSlotMapFile
;
56 SvIdlDataBase::~SvIdlDataBase()
61 #define ADD_TYPE( Name ) \
62 aTypeList.push_back( new SvMetaType( SvHash_##Name()->GetName() ) );
64 SvRefMemberList
<SvMetaType
*>& SvIdlDataBase::GetTypeList()
66 if( aTypeList
.empty() )
68 aTypeList
.push_back( new SvMetaTypeString() );
69 aTypeList
.push_back( new SvMetaTypevoid() );
71 // MI: IDispatch::Invoke can not unsigned
80 ADD_TYPE( SbxObject
);
82 // Attention! When adding types all binary data bases get incompatible
88 void SvIdlDataBase::SetError( const OString
& rError
, SvToken
const & rTok
)
90 if( rTok
.GetLine() > 10000 )
91 aError
.SetText( "line count overflow" );
93 if( aError
.nLine
< rTok
.GetLine()
94 || (aError
.nLine
== rTok
.GetLine() && aError
.nColumn
< rTok
.GetColumn()) )
96 aError
= SvIdlError( rTok
.GetLine(), rTok
.GetColumn() );
97 aError
.SetText( rError
);
101 void SvIdlDataBase::SetAndWriteError( SvTokenStream
& rInStm
, const OString
& rError
)
103 SetError( rError
, rInStm
.GetToken() );
104 WriteError( rInStm
);
107 void SvIdlDataBase::Push( SvMetaObject
* pObj
)
109 GetStack().push_back( pObj
);
112 bool SvIdlDataBase::FindId( const OString
& rIdName
, sal_uInt32
* pVal
)
117 if( pIdTable
->Test( rIdName
, &nHash
) )
119 *pVal
= pIdTable
->Get( nHash
)->GetValue();
126 void SvIdlDataBase::InsertId( const OString
& rIdName
, sal_uInt32 nVal
)
129 pIdTable
.reset( new SvStringHashTable
);
132 pIdTable
->Insert( rIdName
, &nHash
)->SetValue( nVal
);
135 bool SvIdlDataBase::ReadIdFile( std::string_view rOFileName
)
137 OUString rFileName
= OStringToOUString(rOFileName
, RTL_TEXTENCODING_ASCII_US
);
139 osl::File::searchFileURL( rFileName
, GetPath(), aFullName
);
140 osl::FileBase::getSystemPathFromFileURL( aFullName
, aFullName
);
142 for ( size_t i
= 0, n
= aIdFileList
.size(); i
< n
; ++i
)
143 if ( aIdFileList
[ i
] == rFileName
)
146 aIdFileList
.push_back( rFileName
);
147 AddDepFile( aFullName
);
148 SvTokenStream
aTokStm( aFullName
);
149 if( aTokStm
.GetStream().GetError() != ERRCODE_NONE
)
152 SvToken
& rTok
= aTokStm
.GetToken_Next();
154 while( !rTok
.IsEof() )
156 if( rTok
.IsChar() && rTok
.GetChar() == '#' )
158 rTok
= aTokStm
.GetToken_Next();
159 if( rTok
.Is( SvHash_define() ) )
161 rTok
= aTokStm
.GetToken_Next();
163 if( !rTok
.IsIdentifier() )
164 throw SvParseException( "unexpected token after define", rTok
);
165 aDefName
= rTok
.GetString();
171 rTok
= aTokStm
.GetToken_Next();
172 if (rTok
.GetTokenAsString().startsWith("TypedWhichId"))
174 rTok
= aTokStm
.GetToken_Next();
175 if( !rTok
.IsChar() || rTok
.GetChar() != '<')
176 throw SvParseException( "expected '<'", rTok
);
177 rTok
= aTokStm
.GetToken_Next();
178 if (rTok
.IsChar() && rTok
.GetChar() == ':')
180 // add support for "::avmedia::MediaItem" namespaced identifier
181 rTok
= aTokStm
.GetToken_Next();
182 if( !rTok
.IsChar() || rTok
.GetChar() != ':')
183 throw SvParseException( "expected ':'", rTok
);
184 // the lexer reads "avmedia::MediaItem" as an identifier
185 rTok
= aTokStm
.GetToken_Next();
186 if( !rTok
.IsIdentifier() )
187 throw SvParseException( "expected identifier", rTok
);
189 else if( !rTok
.IsIdentifier() )
190 throw SvParseException( "expected identifier", rTok
);
191 rTok
= aTokStm
.GetToken_Next();
192 if( !rTok
.IsChar() || rTok
.GetChar() != '>')
193 throw SvParseException( "expected '<'", rTok
);
194 rTok
= aTokStm
.GetToken_Next();
196 else if( rTok
.IsIdentifier() )
199 if( FindId( rTok
.GetString(), &n
) )
204 else if( rTok
.IsChar() )
206 if( rTok
.GetChar() == '-'
207 || rTok
.GetChar() == '/'
208 || rTok
.GetChar() == '*'
209 || rTok
.GetChar() == '&'
210 || rTok
.GetChar() == '|'
211 || rTok
.GetChar() == '^'
212 || rTok
.GetChar() == '~' )
214 throw SvParseException( "unknown operator '" + OStringChar(rTok
.GetChar()) + "'in define", rTok
);
216 if( rTok
.GetChar() != '+'
217 && rTok
.GetChar() != '('
218 && rTok
.GetChar() != ')' )
219 // only + is allowed, parentheses are immaterial
220 // because + is commutative
223 else if( rTok
.IsInteger() )
225 nVal
+= rTok
.GetNumber();
232 InsertId( aDefName
, nVal
);
235 else if( rTok
.Is( SvHash_include() ) )
237 rTok
= aTokStm
.GetToken_Next();
238 OStringBuffer
aNameBuf(128);
239 if( rTok
.IsString() )
240 aNameBuf
.append(rTok
.GetString());
241 else if( rTok
.IsChar() && rTok
.GetChar() == '<' )
243 rTok
= aTokStm
.GetToken_Next();
245 && !(rTok
.IsChar() && rTok
.GetChar() == '>') )
247 aNameBuf
.append(rTok
.GetTokenAsString());
248 rTok
= aTokStm
.GetToken_Next();
252 throw SvParseException("unexpected eof in #include", rTok
);
255 OString
aName(aNameBuf
.makeStringAndClear());
256 if (aName
== "sfx2/groupid.hxx")
258 // contains C++ code which we cannot parse
259 // we special-case this by defining a macro internally in...
261 else if (aName
== "svl/typedwhich.hxx")
263 // contains C++ code which we cannot parse
265 else if (!ReadIdFile(aName
))
267 throw SvParseException("cannot read file: " + aName
, rTok
);
272 rTok
= aTokStm
.GetToken_Next();
277 SvMetaType
* SvIdlDataBase::FindType( const SvMetaType
* pPType
,
278 SvRefMemberList
<SvMetaType
*>& rList
)
280 for (auto const& elem
: rList
)
286 SvMetaType
* SvIdlDataBase::FindType( std::string_view rName
)
288 for (auto const& elem
: aTypeList
)
289 if( rName
== elem
->GetName() )
294 SvMetaType
* SvIdlDataBase::ReadKnownType( SvTokenStream
& rInStm
)
296 sal_uInt32 nTokPos
= rInStm
.Tell();
297 SvToken
& rTok
= rInStm
.GetToken_Next();
299 if( rTok
.IsIdentifier() )
301 const OString
& aName
= rTok
.GetString();
302 for( const auto& aType
: GetTypeList() )
304 if( aType
->GetName() == aName
)
310 rInStm
.Seek( nTokPos
);
314 SvMetaAttribute
* SvIdlDataBase::ReadKnownAttr
316 SvTokenStream
& rInStm
,
317 SvMetaType
* pType
/* If pType == NULL, then the type has
321 sal_uInt32 nTokPos
= rInStm
.Tell();
324 pType
= ReadKnownType( rInStm
);
329 SvToken
& rTok
= rInStm
.GetToken_Next();
330 if( rTok
.IsIdentifier() )
333 if( FindId( rTok
.GetString(), &n
) )
335 for( size_t i
= 0; i
< aSlotList
.size(); i
++ )
337 SvMetaSlot
* pSlot
= aSlotList
[i
];
338 if( pSlot
->GetSlotId().getString() == rTok
.GetString() )
343 OSL_FAIL(OString("Not found : " + rTok
.GetString()).getStr());
347 rInStm
.Seek( nTokPos
);
351 SvMetaAttribute
* SvIdlDataBase::FindKnownAttr( const SvIdentifier
& rId
)
354 if( FindId( rId
.getString(), &n
) )
356 for( size_t i
= 0; i
< aSlotList
.size(); i
++ )
358 SvMetaSlot
* pSlot
= aSlotList
[i
];
359 if( pSlot
->GetSlotId().getString() == rId
.getString() )
367 SvMetaClass
* SvIdlDataBase::ReadKnownClass( SvTokenStream
& rInStm
)
369 sal_uInt32 nTokPos
= rInStm
.Tell();
370 SvToken
& rTok
= rInStm
.GetToken_Next();
372 if( rTok
.IsIdentifier() )
374 SvMetaClass
* p
= FindKnownClass(rTok
.GetString());
379 rInStm
.Seek( nTokPos
);
383 SvMetaClass
* SvIdlDataBase::FindKnownClass( std::string_view aName
)
385 for( size_t n
= 0; n
< aClassList
.size(); n
++ )
387 SvMetaClass
* pClass
= aClassList
[n
];
388 if( pClass
->GetName() == aName
)
394 void SvIdlDataBase::Write(const OString
& rText
) const
396 if( nVerbosity
!= 0 )
397 fprintf( stdout
, "%s", rText
.getStr() );
400 void SvIdlDataBase::WriteError( SvTokenStream
& rInStm
)
403 OUString
aFileName( rInStm
.GetFileName() );
404 OStringBuffer aErrorText
;
405 sal_uInt64 nRow
= 0, nColumn
= 0;
408 SvToken
& rTok
= rInStm
.GetToken();
411 nRow
= rTok
.GetLine();
412 nColumn
= rTok
.GetColumn();
414 if( aError
.IsError() )
416 // search error token
418 if( !aError
.GetText().isEmpty() )
420 aErrorText
.append("may be <" + aError
.GetText());
422 SvToken
* pPrevTok
= nullptr;
423 while( &rTok
!= pPrevTok
)
426 if( rTok
.GetLine() == aError
.nLine
427 && rTok
.GetColumn() == aError
.nColumn
)
429 rTok
= rInStm
.GetToken_PrevAll();
433 aErrorText
.append("> at ( "
434 + OString::number(static_cast<sal_Int64
>(aError
.nLine
))
436 + OString::number(static_cast<sal_Int64
>(aError
.nColumn
))
440 aError
= SvIdlError();
444 fprintf( stderr
, "\n%s --- %s: ( %" SAL_PRIuUINT64
", %" SAL_PRIuUINT64
" )\n",
445 OUStringToOString(aFileName
, RTL_TEXTENCODING_UTF8
).getStr(),
446 "error", nRow
, nColumn
);
448 if( !aErrorText
.isEmpty() )
450 fprintf( stderr
, "\t%s\n", aErrorText
.getStr() );
453 // look for identifier close by
454 if( !rTok
.IsIdentifier() )
456 rInStm
.GetToken_PrevAll();
457 rTok
= rInStm
.GetToken();
459 if( rTok
.IsIdentifier() )
461 OString aN
= GetIdlApp().pHashTable
->GetNearString( rTok
.GetString() );
463 fprintf( stderr
, "%s versus %s\n", rTok
.GetString().getStr(), aN
.getStr() );
467 SvIdlWorkingBase::SvIdlWorkingBase(const SvCommand
& rCmd
) : SvIdlDataBase(rCmd
)
472 bool SvIdlWorkingBase::WriteSfx( SvStream
& rOutStm
)
474 if( rOutStm
.GetError() != ERRCODE_NONE
)
477 // reset all tmp variables for writing
479 SvMemoryStream
aTmpStm( 256000, 256000 );
481 for( n
= 0; n
< GetModuleList().size(); n
++ )
483 SvMetaModule
* pModule
= GetModuleList()[n
];
484 pModule
->WriteSfx( *this, aTmpStm
);
487 for( n
= 0; n
< aUsedTypes
.size(); n
++ )
489 SvMetaType
* pType
= aUsedTypes
[n
];
490 pType
->WriteSfx( *this, rOutStm
);
493 rOutStm
.WriteStream( aTmpStm
);
497 void SvIdlDataBase::StartNewFile( std::u16string_view rName
)
499 bExport
= aExportFile
.equalsIgnoreAsciiCase( rName
);
503 void SvIdlDataBase::AppendSlot( SvMetaSlot
*pSlot
)
505 aSlotList
.push_back( pSlot
);
509 void SvIdlDataBase::AddDepFile(OUString
const& rFileName
)
511 m_DepFiles
.insert(rFileName
);
518 SvFileStream
& m_rStream
;
519 explicit WriteDep(SvFileStream
& rStream
) : m_rStream(rStream
) { }
520 void operator() (std::u16string_view rItem
)
522 m_rStream
.WriteOString( " \\\n " );
523 m_rStream
.WriteOString( OUStringToOString(rItem
, RTL_TEXTENCODING_UTF8
) );
527 // write a dummy target for one included file, so the incremental build does
528 // not break with "No rule to make target" if the included file is removed
531 SvFileStream
& m_rStream
;
532 explicit WriteDummy(SvFileStream
& rStream
) : m_rStream(rStream
) { }
533 void operator() (std::u16string_view rItem
)
535 m_rStream
.WriteOString( OUStringToOString(rItem
, RTL_TEXTENCODING_UTF8
) );
536 m_rStream
.WriteOString( " :\n\n" );
542 void SvIdlDataBase::WriteDepFile(
543 SvFileStream
& rStream
, std::u16string_view rTarget
)
545 rStream
.WriteOString( OUStringToOString(rTarget
, RTL_TEXTENCODING_UTF8
) );
546 rStream
.WriteOString( " :" );
547 ::std::for_each(m_DepFiles
.begin(), m_DepFiles
.end(), WriteDep(rStream
));
548 rStream
.WriteOString( "\n\n" );
549 ::std::for_each(m_DepFiles
.begin(), m_DepFiles
.end(), WriteDummy(rStream
));
552 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */