1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "sal/config.h"
36 #include "boost/scoped_ptr.hpp"
37 #include "rtl/strbuf.hxx"
41 #include "cfgmerge.hxx"
44 void yyerror(char const *);
50 bool mergeMode
= false;
53 char const * prjRoot
= 0;
54 char const * inputPathname
= 0;
55 char const * outputPathname
= 0;
56 char const * mergeSrc
;
57 boost::scoped_ptr
< CfgParser
> parser
;
61 void handleArguments(int argc
, char ** argv
) {
62 for (int i
= 1; i
!= argc
; ++i
) {
63 if (std::strcmp(argv
[i
], "-e") == 0) {
64 global::errorLog
= false;
65 } else if (std::strcmp(argv
[i
], "-i") == 0) {
67 global::inputPathname
= 0; // no valid command line
70 global::inputPathname
= argv
[i
];
71 } else if (std::strcmp(argv
[i
], "-l") == 0) {
73 global::inputPathname
= 0; // no valid command line
76 Export::sLanguages
= argv
[i
];
77 } else if (std::strcmp(argv
[i
], "-m") == 0) {
79 global::inputPathname
= 0; // no valid command line
82 global::mergeSrc
= argv
[i
];
83 global::mergeMode
= true;
84 } else if (std::strcmp(argv
[i
], "-o") == 0) {
86 global::inputPathname
= 0; // no valid command line
89 global::outputPathname
= argv
[i
];
90 } else if (std::strcmp(argv
[i
], "-p") == 0) {
92 global::inputPathname
= 0; // no valid command line
95 global::prj
= argv
[i
];
96 } else if (std::strcmp(argv
[i
], "-r") == 0) {
98 global::inputPathname
= 0; // no valid command line
101 global::prjRoot
= argv
[i
];
103 global::inputPathname
= 0; // no valid command line
107 if (global::inputPathname
== 0 || global::outputPathname
== 0) {
110 ("Syntax: cfgex [-p Prj] [-r PrjRoot] -i FileIn -o FileOut"
111 " [-m DataBase] [-e] [-l l1,l2,...]\n"
113 " PrjRoot: Path to project root (../.. etc.)\n"
114 " FileIn: Source files (*.src)\n"
115 " FileOut: Destination file (*.*)\n"
116 " DataBase: Mergedata (*.sdf)\n"
117 " -e: Disable writing errorlog\n"
118 " -l: Restrict the handled languages; l1, l2, ... are elements of"
119 " (de, en-US, ...)\n"));
120 std::exit(EXIT_FAILURE
);
122 Export::InitLanguages();
129 FILE * init(int argc
, char ** argv
) {
130 handleArguments(argc
, argv
);
132 FILE * pFile
= std::fopen(global::inputPathname
, "r");
135 stderr
, "Error: Cannot open file \"%s\"\n",
136 global::inputPathname
);
137 std::exit(EXIT_FAILURE
);
140 if (global::mergeMode
) {
141 global::parser
.reset(
143 global::mergeSrc
, global::outputPathname
,
144 global::inputPathname
));
146 global::parser
.reset(
148 global::outputPathname
, global::prj
,
149 common::pathnameToken(global::inputPathname
, global::prjRoot
)));
155 void workOnTokenSet(int nTyp
, char * pTokenText
) {
156 global::parser
->Execute( nTyp
, pTokenText
);
162 // class CfgStackData
165 CfgStackData
* CfgStack::Push(const rtl::OString
&rTag
, const rtl::OString
&rId
)
167 CfgStackData
*pD
= new CfgStackData( rTag
, rId
);
168 maList
.push_back( pD
);
176 /*****************************************************************************/
177 CfgStack::~CfgStack()
178 /*****************************************************************************/
180 for ( size_t i
= 0, n
= maList
.size(); i
< n
; i
++ )
185 rtl::OString
CfgStack::GetAccessPath( size_t nPos
)
187 rtl::OStringBuffer sReturn
;
188 for (size_t i
= 0; i
<= nPos
; ++i
)
192 sReturn
.append(maList
[i
]->GetIdentifier());
195 return sReturn
.makeStringAndClear();
198 /*****************************************************************************/
199 CfgStackData
*CfgStack::GetStackData()
200 /*****************************************************************************/
203 return maList
[maList
.size() - 1];
212 /*****************************************************************************/
213 CfgParser::CfgParser()
214 /*****************************************************************************/
215 : pStackData( NULL
),
216 bLocalize( sal_False
)
220 CfgParser::~CfgParser()
224 sal_Bool
CfgParser::IsTokenClosed(const rtl::OString
&rToken
)
226 return rToken
[rToken
.getLength() - 2] == '/';
229 /*****************************************************************************/
230 void CfgParser::AddText(
232 const rtl::OString
&rIsoLang
,
233 const rtl::OString
&rResTyp
235 /*****************************************************************************/
237 rText
= rText
.replaceAll(rtl::OString('\n'), rtl::OString()).
238 replaceAll(rtl::OString('\r'), rtl::OString()).
239 replaceAll(rtl::OString('\t'), rtl::OString());
240 pStackData
->sResTyp
= rResTyp
;
241 WorkOnText( rText
, rIsoLang
);
242 pStackData
->sText
[ rIsoLang
] = rText
;
245 /*****************************************************************************/
246 int CfgParser::ExecuteAnalyzedToken( int nToken
, char *pToken
)
247 /*****************************************************************************/
249 rtl::OString
sToken( pToken
);
251 if ( sToken
== " " || sToken
== "\t" )
252 sLastWhitespace
+= sToken
;
254 rtl::OString sTokenName
;
255 rtl::OString sTokenId
;
257 sal_Bool bOutput
= sal_True
;
260 case CFG_TOKEN_PACKAGE
:
261 case CFG_TOKEN_COMPONENT
:
262 case CFG_TOKEN_TEMPLATE
:
263 case CFG_TOKEN_CONFIGNAME
:
264 case CFG_TOKEN_OORNAME
:
265 case CFG_TOKEN_OORVALUE
:
270 sTokenName
= sToken
.getToken(1, '<').getToken(0, '>').
273 if ( !IsTokenClosed( sToken
)) {
274 rtl::OString sSearch
;
276 case CFG_TOKEN_PACKAGE
:
277 sSearch
= "package-id=";
279 case CFG_TOKEN_COMPONENT
:
280 sSearch
= "component-id=";
282 case CFG_TOKEN_TEMPLATE
:
283 sSearch
= "template-id=";
285 case CFG_TOKEN_CONFIGNAME
:
286 sSearch
= "cfg:name=";
288 case CFG_TOKEN_OORNAME
:
289 sSearch
= "oor:name=";
290 bLocalize
= sal_True
;
292 case CFG_TOKEN_OORVALUE
:
293 sSearch
= "oor:value=";
295 case CFG_TEXT_START
: {
296 if ( sCurrentResTyp
!= sTokenName
) {
297 WorkOnRessourceEnd();
299 for( unsigned int i
= 0; i
< aLanguages
.size(); ++i
){
300 sCur
= aLanguages
[ i
];
301 pStackData
->sText
[ sCur
] = rtl::OString();
304 sCurrentResTyp
= sTokenName
;
306 rtl::OString sTemp
= sToken
.copy( sToken
.indexOf( "xml:lang=" ));
307 sCurrentIsoLang
= sTemp
.getToken(1, '"');
309 if ( sCurrentIsoLang
== NO_TRANSLATE_ISO
)
310 bLocalize
= sal_False
;
312 pStackData
->sTextTag
= sToken
;
318 if ( !sSearch
.isEmpty())
320 rtl::OString sTemp
= sToken
.copy( sToken
.indexOf( sSearch
));
321 sTokenId
= sTemp
.getToken(1, '"');
323 pStackData
= aStack
.Push( sTokenName
, sTokenId
);
325 if ( sSearch
== "cfg:name=" ) {
326 rtl::OString
sTemp( sToken
.toAsciiUpperCase() );
327 bLocalize
= (( sTemp
.indexOf( "CFG:TYPE=\"STRING\"" ) != -1 ) &&
328 ( sTemp
.indexOf( "CFG:LOCALIZED=\"sal_True\"" ) != -1 ));
331 else if ( sTokenName
== "label" ) {
332 if ( sCurrentResTyp
!= sTokenName
) {
333 WorkOnRessourceEnd();
335 for( unsigned int i
= 0; i
< aLanguages
.size(); ++i
){
336 sCur
= aLanguages
[ i
];
337 pStackData
->sText
[ sCur
] = rtl::OString();
340 sCurrentResTyp
= sTokenName
;
346 sTokenName
= sToken
.getToken(1, '/').getToken(0, '>').
348 if ( aStack
.GetStackData() && ( aStack
.GetStackData()->GetTagType() == sTokenName
))
350 if (sCurrentText
.isEmpty())
351 WorkOnRessourceEnd();
353 pStackData
= aStack
.GetStackData();
357 rtl::OString
sError( "Misplaced close tag: " );
358 rtl::OString
sInFile(" in file ");
361 sError
+= global::inputPathname
;
363 std::exit(EXIT_FAILURE
);
369 sCurrentText
+= sToken
;
373 case CFG_TOKEN_NO_TRANSLATE
:
374 bLocalize
= sal_False
;
378 if ( !sCurrentText
.isEmpty() && nToken
!= CFG_TEXTCHAR
)
380 AddText( sCurrentText
, sCurrentIsoLang
, sCurrentResTyp
);
381 Output( sCurrentText
);
382 sCurrentText
= rtl::OString();
383 pStackData
->sEndTextTag
= sToken
;
389 if ( sToken
!= " " && sToken
!= "\t" )
390 sLastWhitespace
= "";
395 void CfgExport::Output(const rtl::OString
&)
399 /*****************************************************************************/
400 int CfgParser::Execute( int nToken
, char * pToken
)
401 /*****************************************************************************/
403 rtl::OString
sToken( pToken
);
407 if ( sToken
.indexOf( "package-id=" ) != -1 )
408 return ExecuteAnalyzedToken( CFG_TOKEN_PACKAGE
, pToken
);
409 else if ( sToken
.indexOf( "component-id=" ) != -1 )
410 return ExecuteAnalyzedToken( CFG_TOKEN_COMPONENT
, pToken
);
411 else if ( sToken
.indexOf( "template-id=" ) != -1 )
412 return ExecuteAnalyzedToken( CFG_TOKEN_TEMPLATE
, pToken
);
413 else if ( sToken
.indexOf( "cfg:name=" ) != -1 )
414 return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME
, pToken
);
415 else if ( sToken
.indexOf( "oor:name=" ) != -1 )
416 return ExecuteAnalyzedToken( CFG_TOKEN_OORNAME
, pToken
);
417 else if ( sToken
.indexOf( "oor:value=" ) != -1 )
418 return ExecuteAnalyzedToken( CFG_TOKEN_OORVALUE
, pToken
);
421 return ExecuteAnalyzedToken( nToken
, pToken
);
424 void CfgParser::Error(const rtl::OString
& rError
)
426 yyerror(rError
.getStr());
430 // class CfgOutputParser
433 CfgOutputParser::CfgOutputParser(const rtl::OString
&rOutputFile
)
436 rOutputFile
.getStr(), std::ios_base::out
| std::ios_base::trunc
);
437 if (!pOutputStream
.is_open())
439 rtl::OStringBuffer
sError(RTL_CONSTASCII_STRINGPARAM("ERROR: Unable to open output file: "));
440 sError
.append(rOutputFile
);
441 Error(sError
.makeStringAndClear());
442 std::exit(EXIT_FAILURE
);
446 /*****************************************************************************/
447 CfgOutputParser::~CfgOutputParser()
448 /*****************************************************************************/
450 pOutputStream
.close();
457 /*****************************************************************************/
458 CfgExport::CfgExport(
459 const rtl::OString
&rOutputFile
,
460 const rtl::OString
&rProject
,
461 const rtl::OString
&rFilePath
463 /*****************************************************************************/
464 : CfgOutputParser( rOutputFile
),
468 Export::InitLanguages( false );
469 aLanguages
= Export::GetLanguages();
472 /*****************************************************************************/
473 CfgExport::~CfgExport()
474 /*****************************************************************************/
478 /*****************************************************************************/
479 void CfgExport::WorkOnRessourceEnd()
480 /*****************************************************************************/
483 if ( pStackData
->sText
[rtl::OString(RTL_CONSTASCII_STRINGPARAM("en-US"))].getLength() )
485 rtl::OString sFallback
= pStackData
->sText
[rtl::OString(RTL_CONSTASCII_STRINGPARAM("en-US"))];
486 rtl::OString sXComment
= pStackData
->sText
[rtl::OString(RTL_CONSTASCII_STRINGPARAM("x-comment"))];
487 rtl::OString sLocalId
= pStackData
->sIdentifier
;
488 rtl::OString sGroupId
;
489 if ( aStack
.size() == 1 ) {
494 sGroupId
= aStack
.GetAccessPath( aStack
.size() - 2 );
497 for (size_t n
= 0; n
< aLanguages
.size(); n
++)
499 rtl::OString sCur
= aLanguages
[ n
];
501 rtl::OString sText
= pStackData
->sText
[ sCur
];
502 if ( sText
.isEmpty())
505 sText
= Export::UnquoteHTML( sText
);
507 rtl::OString
sOutput( sPrj
); sOutput
+= "\t";
510 sOutput
+= pStackData
->sResTyp
; sOutput
+= "\t";
511 sOutput
+= sGroupId
; sOutput
+= "\t";
512 sOutput
+= sLocalId
; sOutput
+= "\t\t\t0\t";
516 sOutput
+= sText
; sOutput
+= "\t";
517 sOutput
+= sXComment
; sOutput
+= "\t\t\t";
519 pOutputStream
<< sOutput
.getStr() << '\n';
525 void CfgExport::WorkOnText(
527 const rtl::OString
&rIsoLang
530 if( rIsoLang
.getLength() ) rText
= Export::UnquoteHTML( rText
);
539 const rtl::OString
&rMergeSource
, const rtl::OString
&rOutputFile
,
540 const rtl::OString
&rFilename
)
541 : CfgOutputParser( rOutputFile
),
542 pMergeDataFile( NULL
),
544 sFilename( rFilename
),
545 bEnglish( sal_False
)
547 if (rMergeSource
.getLength())
549 pMergeDataFile
= new MergeDataFile(
550 rMergeSource
, global::inputPathname
, global::errorLog
, true );
551 if (Export::sLanguages
.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("ALL")))
553 Export::SetLanguages( pMergeDataFile
->GetLanguages() );
554 aLanguages
= pMergeDataFile
->GetLanguages();
556 else aLanguages
= Export::GetLanguages();
559 aLanguages
= Export::GetLanguages();
562 /*****************************************************************************/
563 CfgMerge::~CfgMerge()
564 /*****************************************************************************/
566 delete pMergeDataFile
;
570 void CfgMerge::WorkOnText(rtl::OString
&rText
, const rtl::OString
& rLangIndex
)
573 if ( pMergeDataFile
&& bLocalize
) {
575 rtl::OString sLocalId
= pStackData
->sIdentifier
;
576 rtl::OString sGroupId
;
577 if ( aStack
.size() == 1 ) {
579 sLocalId
= rtl::OString();
582 sGroupId
= aStack
.GetAccessPath( aStack
.size() - 2 );
585 rtl::OString sPlatform
;
587 pResData
= new ResData( sPlatform
, sGroupId
, sFilename
);
588 pResData
->sId
= sLocalId
;
589 pResData
->sResTyp
= pStackData
->sResTyp
;
592 if (rLangIndex
.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")))
595 PFormEntrys
*pEntrys
= pMergeDataFile
->GetPFormEntrysCaseSensitive( pResData
);
597 rtl::OString sContent
;
598 pEntrys
->GetText( sContent
, STRING_TYP_TEXT
, rLangIndex
);
600 if ( Export::isAllowed( rLangIndex
) &&
601 ( sContent
!= "-" ) && !sContent
.isEmpty())
603 rText
= Export::QuoteHTML( rText
);
609 void CfgMerge::Output(const rtl::OString
& rOutput
)
611 pOutputStream
<< rOutput
.getStr();
614 /*****************************************************************************/
615 void CfgMerge::WorkOnRessourceEnd()
616 /*****************************************************************************/
619 if ( pMergeDataFile
&& pResData
&& bLocalize
&& bEnglish
) {
620 PFormEntrys
*pEntrys
= pMergeDataFile
->GetPFormEntrysCaseSensitive( pResData
);
624 for( unsigned int i
= 0; i
< aLanguages
.size(); ++i
){
625 sCur
= aLanguages
[ i
];
627 rtl::OString sContent
;
628 pEntrys
->GetText( sContent
, STRING_TYP_TEXT
, sCur
, sal_True
);
630 ( !sCur
.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")) ) &&
632 ( sContent
!= "-" ) && !sContent
.isEmpty())
635 rtl::OString sText
= Export::QuoteHTML( sContent
);
637 rtl::OString
sAdditionalLine( "\t" );
639 rtl::OString sTextTag
= pStackData
->sTextTag
;
640 rtl::OString sTemp
= sTextTag
.copy( sTextTag
.indexOf( "xml:lang=" ));
643 rtl::OString sSearch
= sTemp
.getToken(0, '"', n
);
645 sSearch
+= sTemp
.getToken(0, '"', n
);
648 rtl::OString sReplace
= sTemp
.getToken(0, '"');
653 sTextTag
= sTextTag
.replaceFirst(sSearch
, sReplace
);
655 sAdditionalLine
+= sTextTag
;
656 sAdditionalLine
+= sText
;
657 sAdditionalLine
+= pStackData
->sEndTextTag
;
659 sAdditionalLine
+= "\n";
660 sAdditionalLine
+= sLastWhitespace
;
662 Output( sAdditionalLine
);
669 bEnglish
= sal_False
;
672 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */