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"
29 #include "boost/scoped_ptr.hpp"
30 #include "rtl/strbuf.hxx"
34 #include "cfgmerge.hxx"
37 void yyerror(char const *);
43 OString inputPathname
;
44 boost::scoped_ptr
< CfgParser
> parser
;
51 FILE * init(int argc
, char ** argv
) {
53 common::HandledArgs aArgs
;
54 if ( !common::handleArguments(argc
, argv
, aArgs
) )
56 common::writeUsage("cfgex","*.xcu");
57 std::exit(EXIT_FAILURE
);
59 global::inputPathname
= aArgs
.m_sInputFile
;
61 FILE * pFile
= std::fopen(global::inputPathname
.getStr(), "r");
64 stderr
, "Error: Cannot open file \"%s\"\n",
65 global::inputPathname
.getStr() );
66 std::exit(EXIT_FAILURE
);
69 if (aArgs
.m_bMergeMode
) {
72 aArgs
.m_sMergeSrc
, aArgs
.m_sOutputFile
,
73 global::inputPathname
, aArgs
.m_sLanguage
));
77 aArgs
.m_sOutputFile
, global::inputPathname
));
83 void workOnTokenSet(int nTyp
, char * pTokenText
) {
84 global::parser
->Execute( nTyp
, pTokenText
);
93 CfgStackData
* CfgStack::Push(const OString
&rTag
, const OString
&rId
)
95 CfgStackData
*pD
= new CfgStackData( rTag
, rId
);
96 maList
.push_back( pD
);
104 CfgStack::~CfgStack()
106 for ( size_t i
= 0, n
= maList
.size(); i
< n
; i
++ )
111 OString
CfgStack::GetAccessPath( size_t nPos
)
113 OStringBuffer sReturn
;
114 for (size_t i
= 0; i
<= nPos
; ++i
)
118 sReturn
.append(maList
[i
]->GetIdentifier());
121 return sReturn
.makeStringAndClear();
124 CfgStackData
*CfgStack::GetStackData()
127 return maList
[maList
.size() - 1];
136 CfgParser::CfgParser()
137 : pStackData( NULL
),
142 CfgParser::~CfgParser()
146 bool CfgParser::IsTokenClosed(const OString
&rToken
)
148 return rToken
[rToken
.getLength() - 2] == '/';
151 void CfgParser::AddText(
153 const OString
&rIsoLang
,
154 const OString
&rResTyp
)
156 rText
= rText
.replaceAll(OString('\n'), OString()).
157 replaceAll(OString('\r'), OString()).
158 replaceAll(OString('\t'), OString());
159 pStackData
->sResTyp
= rResTyp
;
160 WorkOnText( rText
, rIsoLang
);
161 pStackData
->sText
[ rIsoLang
] = rText
;
164 int CfgParser::ExecuteAnalyzedToken( int nToken
, char *pToken
)
166 OString
sToken( pToken
);
168 if ( sToken
== " " || sToken
== "\t" )
169 sLastWhitespace
+= sToken
;
177 case CFG_TOKEN_PACKAGE
:
178 case CFG_TOKEN_COMPONENT
:
179 case CFG_TOKEN_TEMPLATE
:
180 case CFG_TOKEN_CONFIGNAME
:
181 case CFG_TOKEN_OORNAME
:
182 case CFG_TOKEN_OORVALUE
:
187 sTokenName
= sToken
.getToken(1, '<').getToken(0, '>').
190 if ( !IsTokenClosed( sToken
)) {
193 case CFG_TOKEN_PACKAGE
:
194 sSearch
= "package-id=";
196 case CFG_TOKEN_COMPONENT
:
197 sSearch
= "component-id=";
199 case CFG_TOKEN_TEMPLATE
:
200 sSearch
= "template-id=";
202 case CFG_TOKEN_CONFIGNAME
:
203 sSearch
= "cfg:name=";
205 case CFG_TOKEN_OORNAME
:
206 sSearch
= "oor:name=";
209 case CFG_TOKEN_OORVALUE
:
210 sSearch
= "oor:value=";
212 case CFG_TEXT_START
: {
213 if ( sCurrentResTyp
!= sTokenName
) {
216 sCurrentResTyp
= sTokenName
;
218 OString sTemp
= sToken
.copy( sToken
.indexOf( "xml:lang=" ));
219 sCurrentIsoLang
= sTemp
.getToken(1, '"');
221 if ( sCurrentIsoLang
== NO_TRANSLATE_ISO
)
224 pStackData
->sTextTag
= sToken
;
230 if ( !sSearch
.isEmpty())
232 OString sTemp
= sToken
.copy( sToken
.indexOf( sSearch
));
233 sTokenId
= sTemp
.getToken(1, '"');
235 pStackData
= aStack
.Push( sTokenName
, sTokenId
);
237 if ( sSearch
== "cfg:name=" ) {
238 OString
sTemp( sToken
.toAsciiUpperCase() );
239 bLocalize
= (( sTemp
.indexOf( "CFG:TYPE=\"STRING\"" ) != -1 ) &&
240 ( sTemp
.indexOf( "CFG:LOCALIZED=\"sal_True\"" ) != -1 ));
243 else if ( sTokenName
== "label" ) {
244 if ( sCurrentResTyp
!= sTokenName
) {
247 sCurrentResTyp
= sTokenName
;
253 sTokenName
= sToken
.getToken(1, '/').getToken(0, '>').
255 if ( aStack
.GetStackData() && ( aStack
.GetStackData()->GetTagType() == sTokenName
))
257 if (sCurrentText
.isEmpty())
260 pStackData
= aStack
.GetStackData();
264 OString
sError( "Misplaced close tag: " );
265 OString
sInFile(" in file ");
268 sError
+= global::inputPathname
;
270 std::exit(EXIT_FAILURE
);
276 sCurrentText
+= sToken
;
280 case CFG_TOKEN_NO_TRANSLATE
:
285 if ( !sCurrentText
.isEmpty() && nToken
!= CFG_TEXTCHAR
)
287 AddText( sCurrentText
, sCurrentIsoLang
, sCurrentResTyp
);
288 Output( sCurrentText
);
289 sCurrentText
.clear();
290 pStackData
->sEndTextTag
= sToken
;
296 if ( sToken
!= " " && sToken
!= "\t" )
297 sLastWhitespace
= "";
302 void CfgExport::Output(const OString
&)
306 int CfgParser::Execute( int nToken
, char * pToken
)
308 OString
sToken( pToken
);
312 if ( sToken
.indexOf( "package-id=" ) != -1 )
313 return ExecuteAnalyzedToken( CFG_TOKEN_PACKAGE
, pToken
);
314 else if ( sToken
.indexOf( "component-id=" ) != -1 )
315 return ExecuteAnalyzedToken( CFG_TOKEN_COMPONENT
, pToken
);
316 else if ( sToken
.indexOf( "template-id=" ) != -1 )
317 return ExecuteAnalyzedToken( CFG_TOKEN_TEMPLATE
, pToken
);
318 else if ( sToken
.indexOf( "cfg:name=" ) != -1 )
319 return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME
, pToken
);
320 else if ( sToken
.indexOf( "oor:name=" ) != -1 )
321 return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME
, pToken
);
322 else if ( sToken
.indexOf( "oor:value=" ) != -1 )
323 return ExecuteAnalyzedToken( CFG_TOKEN_OORVALUE
, pToken
);
326 return ExecuteAnalyzedToken( nToken
, pToken
);
329 void CfgParser::Error(const OString
& rError
)
331 yyerror(rError
.getStr());
338 CfgExport::CfgExport(
339 const OString
&rOutputFile
,
340 const OString
&rFilePath
)
344 pOutputStream
.open( rOutputFile
, PoOfstream::APP
);
345 if (!pOutputStream
.isOpen())
347 std::cerr
<< "ERROR: Unable to open output file: " << rOutputFile
<< "\n";
348 std::exit(EXIT_FAILURE
);
352 CfgExport::~CfgExport()
354 pOutputStream
.close();
358 void CfgExport::WorkOnResourceEnd()
361 if ( !pStackData
->sText
["en-US"].isEmpty() )
363 OString sXComment
= pStackData
->sText
[OString("x-comment")];
364 OString sLocalId
= pStackData
->sIdentifier
;
366 if ( aStack
.size() == 1 ) {
371 sGroupId
= aStack
.GetAccessPath( aStack
.size() - 2 );
375 OString sText
= pStackData
->sText
[ "en-US" ];
376 sText
= helper::UnQuotHTML( sText
);
378 common::writePoEntry(
379 "Cfgex", pOutputStream
, sPath
, pStackData
->sResTyp
,
380 sGroupId
, sLocalId
, sXComment
, sText
);
385 void CfgExport::WorkOnText(
387 const OString
&rIsoLang
390 if( !rIsoLang
.isEmpty() ) rText
= helper::UnQuotHTML( rText
);
399 const OString
&rMergeSource
, const OString
&rOutputFile
,
400 const OString
&rFilename
, const OString
&rLanguage
)
401 : pMergeDataFile( NULL
),
403 sFilename( rFilename
),
407 rOutputFile
.getStr(), std::ios_base::out
| std::ios_base::trunc
);
408 if (!pOutputStream
.is_open())
410 std::cerr
<< "ERROR: Unable to open output file: " << rOutputFile
<< "\n";
411 std::exit(EXIT_FAILURE
);
414 if (!rMergeSource
.isEmpty())
416 pMergeDataFile
= new MergeDataFile(
417 rMergeSource
, global::inputPathname
, true );
418 if (rLanguage
.equalsIgnoreAsciiCase("ALL") )
420 aLanguages
= pMergeDataFile
->GetLanguages();
422 else aLanguages
.push_back(rLanguage
);
425 aLanguages
.push_back(rLanguage
);
428 CfgMerge::~CfgMerge()
430 pOutputStream
.close();
431 delete pMergeDataFile
;
435 void CfgMerge::WorkOnText(OString
&, const OString
& rLangIndex
)
438 if ( pMergeDataFile
&& bLocalize
) {
440 OString sLocalId
= pStackData
->sIdentifier
;
442 if ( aStack
.size() == 1 ) {
447 sGroupId
= aStack
.GetAccessPath( aStack
.size() - 2 );
450 pResData
= new ResData( sGroupId
, sFilename
);
451 pResData
->sId
= sLocalId
;
452 pResData
->sResTyp
= pStackData
->sResTyp
;
455 if (rLangIndex
.equalsIgnoreAsciiCase("en-US"))
460 void CfgMerge::Output(const OString
& rOutput
)
462 pOutputStream
<< rOutput
.getStr();
465 void CfgMerge::WorkOnResourceEnd()
468 if ( pMergeDataFile
&& pResData
&& bLocalize
&& bEnglish
) {
469 MergeEntrys
*pEntrys
= pMergeDataFile
->GetMergeEntrysCaseSensitive( pResData
);
473 for( unsigned int i
= 0; i
< aLanguages
.size(); ++i
){
474 sCur
= aLanguages
[ i
];
477 pEntrys
->GetText( sContent
, STRING_TYP_TEXT
, sCur
, true );
479 ( !sCur
.equalsIgnoreAsciiCase("en-US") ) && !sContent
.isEmpty())
482 OString sText
= helper::QuotHTML( sContent
);
484 OString
sAdditionalLine( "\t" );
486 OString sTextTag
= pStackData
->sTextTag
;
487 OString sTemp
= sTextTag
.copy( sTextTag
.indexOf( "xml:lang=" ));
490 OString sSearch
= sTemp
.getToken(0, '"', n
);
492 sSearch
+= sTemp
.getToken(0, '"', n
);
495 OString sReplace
= sTemp
.getToken(0, '"');
500 sTextTag
= sTextTag
.replaceFirst(sSearch
, sReplace
);
502 sAdditionalLine
+= sTextTag
;
503 sAdditionalLine
+= sText
;
504 sAdditionalLine
+= pStackData
->sEndTextTag
;
506 sAdditionalLine
+= "\n";
507 sAdditionalLine
+= sLastWhitespace
;
509 Output( sAdditionalLine
);
519 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */