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 .
21 #include "sal/config.h"
27 #include "boost/scoped_ptr.hpp"
28 #include "rtl/strbuf.hxx"
32 #include "cfgmerge.hxx"
35 void yyerror(char const *);
41 OString inputPathname
;
42 boost::scoped_ptr
< CfgParser
> parser
;
49 FILE * init(int argc
, char ** argv
) {
51 common::HandledArgs aArgs
;
52 if ( !common::handleArguments(argc
, argv
, aArgs
) )
54 common::writeUsage("cfgex","*.xcu");
55 std::exit(EXIT_FAILURE
);
57 global::inputPathname
= aArgs
.m_sInputFile
;
59 FILE * pFile
= std::fopen(global::inputPathname
.getStr(), "r");
62 stderr
, "Error: Cannot open file \"%s\"\n",
63 global::inputPathname
.getStr() );
64 std::exit(EXIT_FAILURE
);
67 if (aArgs
.m_bMergeMode
) {
70 aArgs
.m_sMergeSrc
, aArgs
.m_sOutputFile
,
71 global::inputPathname
, aArgs
.m_sLanguage
));
75 aArgs
.m_sOutputFile
, global::inputPathname
));
81 void workOnTokenSet(int nTyp
, char * pTokenText
) {
82 global::parser
->Execute( nTyp
, pTokenText
);
91 CfgStackData
* CfgStack::Push(const OString
&rTag
, const OString
&rId
)
93 CfgStackData
*pD
= new CfgStackData( rTag
, rId
);
94 maList
.push_back( pD
);
102 CfgStack::~CfgStack()
104 for ( size_t i
= 0, n
= maList
.size(); i
< n
; i
++ )
109 OString
CfgStack::GetAccessPath( size_t nPos
)
111 OStringBuffer sReturn
;
112 for (size_t i
= 0; i
<= nPos
; ++i
)
116 sReturn
.append(maList
[i
]->GetIdentifier());
119 return sReturn
.makeStringAndClear();
122 CfgStackData
*CfgStack::GetStackData()
125 return maList
[maList
.size() - 1];
134 CfgParser::CfgParser()
135 : pStackData( NULL
),
136 bLocalize( sal_False
)
140 CfgParser::~CfgParser()
144 sal_Bool
CfgParser::IsTokenClosed(const OString
&rToken
)
146 return rToken
[rToken
.getLength() - 2] == '/';
149 void CfgParser::AddText(
151 const OString
&rIsoLang
,
152 const OString
&rResTyp
)
154 rText
= rText
.replaceAll(OString('\n'), OString()).
155 replaceAll(OString('\r'), OString()).
156 replaceAll(OString('\t'), OString());
157 pStackData
->sResTyp
= rResTyp
;
158 WorkOnText( rText
, rIsoLang
);
159 pStackData
->sText
[ rIsoLang
] = rText
;
162 int CfgParser::ExecuteAnalyzedToken( int nToken
, char *pToken
)
164 OString
sToken( pToken
);
166 if ( sToken
== " " || sToken
== "\t" )
167 sLastWhitespace
+= sToken
;
172 sal_Bool bOutput
= sal_True
;
175 case CFG_TOKEN_PACKAGE
:
176 case CFG_TOKEN_COMPONENT
:
177 case CFG_TOKEN_TEMPLATE
:
178 case CFG_TOKEN_CONFIGNAME
:
179 case CFG_TOKEN_OORNAME
:
180 case CFG_TOKEN_OORVALUE
:
185 sTokenName
= sToken
.getToken(1, '<').getToken(0, '>').
188 if ( !IsTokenClosed( sToken
)) {
191 case CFG_TOKEN_PACKAGE
:
192 sSearch
= "package-id=";
194 case CFG_TOKEN_COMPONENT
:
195 sSearch
= "component-id=";
197 case CFG_TOKEN_TEMPLATE
:
198 sSearch
= "template-id=";
200 case CFG_TOKEN_CONFIGNAME
:
201 sSearch
= "cfg:name=";
203 case CFG_TOKEN_OORNAME
:
204 sSearch
= "oor:name=";
205 bLocalize
= sal_True
;
207 case CFG_TOKEN_OORVALUE
:
208 sSearch
= "oor:value=";
210 case CFG_TEXT_START
: {
211 if ( sCurrentResTyp
!= sTokenName
) {
214 sCurrentResTyp
= sTokenName
;
216 OString sTemp
= sToken
.copy( sToken
.indexOf( "xml:lang=" ));
217 sCurrentIsoLang
= sTemp
.getToken(1, '"');
219 if ( sCurrentIsoLang
== NO_TRANSLATE_ISO
)
220 bLocalize
= sal_False
;
222 pStackData
->sTextTag
= sToken
;
228 if ( !sSearch
.isEmpty())
230 OString sTemp
= sToken
.copy( sToken
.indexOf( sSearch
));
231 sTokenId
= sTemp
.getToken(1, '"');
233 pStackData
= aStack
.Push( sTokenName
, sTokenId
);
235 if ( sSearch
== "cfg:name=" ) {
236 OString
sTemp( sToken
.toAsciiUpperCase() );
237 bLocalize
= (( sTemp
.indexOf( "CFG:TYPE=\"STRING\"" ) != -1 ) &&
238 ( sTemp
.indexOf( "CFG:LOCALIZED=\"sal_True\"" ) != -1 ));
241 else if ( sTokenName
== "label" ) {
242 if ( sCurrentResTyp
!= sTokenName
) {
245 sCurrentResTyp
= sTokenName
;
251 sTokenName
= sToken
.getToken(1, '/').getToken(0, '>').
253 if ( aStack
.GetStackData() && ( aStack
.GetStackData()->GetTagType() == sTokenName
))
255 if (sCurrentText
.isEmpty())
258 pStackData
= aStack
.GetStackData();
262 OString
sError( "Misplaced close tag: " );
263 OString
sInFile(" in file ");
266 sError
+= global::inputPathname
;
268 std::exit(EXIT_FAILURE
);
274 sCurrentText
+= sToken
;
278 case CFG_TOKEN_NO_TRANSLATE
:
279 bLocalize
= sal_False
;
283 if ( !sCurrentText
.isEmpty() && nToken
!= CFG_TEXTCHAR
)
285 AddText( sCurrentText
, sCurrentIsoLang
, sCurrentResTyp
);
286 Output( sCurrentText
);
287 sCurrentText
= OString();
288 pStackData
->sEndTextTag
= sToken
;
294 if ( sToken
!= " " && sToken
!= "\t" )
295 sLastWhitespace
= "";
300 void CfgExport::Output(const OString
&)
304 int CfgParser::Execute( int nToken
, char * pToken
)
306 OString
sToken( pToken
);
310 if ( sToken
.indexOf( "package-id=" ) != -1 )
311 return ExecuteAnalyzedToken( CFG_TOKEN_PACKAGE
, pToken
);
312 else if ( sToken
.indexOf( "component-id=" ) != -1 )
313 return ExecuteAnalyzedToken( CFG_TOKEN_COMPONENT
, pToken
);
314 else if ( sToken
.indexOf( "template-id=" ) != -1 )
315 return ExecuteAnalyzedToken( CFG_TOKEN_TEMPLATE
, pToken
);
316 else if ( sToken
.indexOf( "cfg:name=" ) != -1 )
317 return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME
, pToken
);
318 else if ( sToken
.indexOf( "oor:name=" ) != -1 )
319 return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME
, pToken
);
320 else if ( sToken
.indexOf( "oor:value=" ) != -1 )
321 return ExecuteAnalyzedToken( CFG_TOKEN_OORVALUE
, pToken
);
324 return ExecuteAnalyzedToken( nToken
, pToken
);
327 void CfgParser::Error(const OString
& rError
)
329 yyerror(rError
.getStr());
336 CfgExport::CfgExport(
337 const OString
&rOutputFile
,
338 const OString
&rFilePath
)
342 pOutputStream
.open( rOutputFile
, PoOfstream::APP
);
343 if (!pOutputStream
.isOpen())
345 std::cerr
<< "ERROR: Unable to open output file: " << rOutputFile
<< "\n";
346 std::exit(EXIT_FAILURE
);
350 CfgExport::~CfgExport()
352 pOutputStream
.close();
356 void CfgExport::WorkOnResourceEnd()
359 if ( pStackData
->sText
[OString(RTL_CONSTASCII_STRINGPARAM("en-US"))].getLength() )
361 OString sXComment
= pStackData
->sText
[OString(RTL_CONSTASCII_STRINGPARAM("x-comment"))];
362 OString sLocalId
= pStackData
->sIdentifier
;
364 if ( aStack
.size() == 1 ) {
369 sGroupId
= aStack
.GetAccessPath( aStack
.size() - 2 );
373 OString sText
= pStackData
->sText
[ "en-US" ];
374 sText
= helper::UnQuotHTML( sText
);
376 common::writePoEntry(
377 "Cfgex", pOutputStream
, sPath
, pStackData
->sResTyp
,
378 sGroupId
, sLocalId
, sXComment
, sText
);
383 void CfgExport::WorkOnText(
385 const OString
&rIsoLang
388 if( rIsoLang
.getLength() ) rText
= helper::UnQuotHTML( rText
);
397 const OString
&rMergeSource
, const OString
&rOutputFile
,
398 const OString
&rFilename
, const OString
&rLanguage
)
399 : pMergeDataFile( NULL
),
401 sFilename( rFilename
),
402 bEnglish( sal_False
)
405 rOutputFile
.getStr(), std::ios_base::out
| std::ios_base::trunc
);
406 if (!pOutputStream
.is_open())
408 std::cerr
<< "ERROR: Unable to open output file: " << rOutputFile
<< "\n";
409 std::exit(EXIT_FAILURE
);
412 if (rMergeSource
.getLength())
414 pMergeDataFile
= new MergeDataFile(
415 rMergeSource
, global::inputPathname
, true );
416 if (rLanguage
.equalsIgnoreAsciiCase("ALL") )
418 aLanguages
= pMergeDataFile
->GetLanguages();
420 else aLanguages
.push_back(rLanguage
);
423 aLanguages
.push_back(rLanguage
);
426 CfgMerge::~CfgMerge()
428 pOutputStream
.close();
429 delete pMergeDataFile
;
433 void CfgMerge::WorkOnText(OString
&, const OString
& rLangIndex
)
436 if ( pMergeDataFile
&& bLocalize
) {
438 OString sLocalId
= pStackData
->sIdentifier
;
440 if ( aStack
.size() == 1 ) {
442 sLocalId
= OString();
445 sGroupId
= aStack
.GetAccessPath( aStack
.size() - 2 );
448 pResData
= new ResData( sGroupId
, sFilename
);
449 pResData
->sId
= sLocalId
;
450 pResData
->sResTyp
= pStackData
->sResTyp
;
453 if (rLangIndex
.equalsIgnoreAsciiCase("en-US"))
458 void CfgMerge::Output(const OString
& rOutput
)
460 pOutputStream
<< rOutput
.getStr();
463 void CfgMerge::WorkOnResourceEnd()
466 if ( pMergeDataFile
&& pResData
&& bLocalize
&& bEnglish
) {
467 MergeEntrys
*pEntrys
= pMergeDataFile
->GetMergeEntrysCaseSensitive( pResData
);
471 for( unsigned int i
= 0; i
< aLanguages
.size(); ++i
){
472 sCur
= aLanguages
[ i
];
475 pEntrys
->GetText( sContent
, STRING_TYP_TEXT
, sCur
, sal_True
);
477 ( !sCur
.equalsIgnoreAsciiCase("en-US") ) && !sContent
.isEmpty())
480 OString sText
= helper::QuotHTML( sContent
);
482 OString
sAdditionalLine( "\t" );
484 OString sTextTag
= pStackData
->sTextTag
;
485 OString sTemp
= sTextTag
.copy( sTextTag
.indexOf( "xml:lang=" ));
488 OString sSearch
= sTemp
.getToken(0, '"', n
);
490 sSearch
+= sTemp
.getToken(0, '"', n
);
493 OString sReplace
= sTemp
.getToken(0, '"');
498 sTextTag
= sTextTag
.replaceFirst(sSearch
, sReplace
);
500 sAdditionalLine
+= sTextTag
;
501 sAdditionalLine
+= sText
;
502 sAdditionalLine
+= pStackData
->sEndTextTag
;
504 sAdditionalLine
+= "\n";
505 sAdditionalLine
+= sLastWhitespace
;
507 Output( sAdditionalLine
);
514 bEnglish
= sal_False
;
517 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */