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"
26 #include "boost/scoped_ptr.hpp"
33 #include <rtl/strbuf.hxx>
35 void yyerror( const char * );
36 void YYWarning( const char * );
40 MergeDataFile
* pMergeDataFile
= 0; //TODO
44 OString inputPathname
;
45 boost::scoped_ptr
< Export
> exporter
;
53 FILE * init(int argc
, char ** argv
) {
55 common::HandledArgs aArgs
;
56 if ( !common::handleArguments(argc
, argv
, aArgs
) )
58 common::writeUsage("transex3","*.src/*.hrc");
59 std::exit(EXIT_FAILURE
);
61 global::inputPathname
= aArgs
.m_sInputFile
;
63 FILE * pFile
= std::fopen(global::inputPathname
.getStr(), "r");
66 stderr
, "Error: Cannot open file \"%s\"\n",
67 global::inputPathname
.getStr());
68 std::exit(EXIT_FAILURE
);
71 if (aArgs
.m_bMergeMode
) {
72 global::exporter
.reset(new Export(aArgs
.m_sMergeSrc
, aArgs
.m_sOutputFile
,
73 aArgs
.m_sLanguage
, aArgs
.m_bUTF8BOM
));
75 global::exporter
.reset(new Export(aArgs
.m_sOutputFile
));
78 global::exporter
->Init();
83 int Parse( int nTyp
, const char *pTokenText
){
84 global::exporter
->Execute( nTyp
, pTokenText
);
88 global::exporter
->pParseQueue
->Close();
89 global::exporter
.reset();
90 // avoid nontrivial Export dtor being executed during exit
93 int WorkOnTokenSet( int nTyp
, char *pTokenText
)
96 global::exporter
->pParseQueue
->Push( QueueEntry( nTyp
, OString(pTokenText
) ) );
106 // set error at global instance of class Export
107 global::exporter
->SetError();
116 // get error at global instance of class Export
117 if (global::exporter
->GetError())
127 sal_Bool
ResData::SetId( const OString
& rId
, sal_uInt16 nLevel
)
129 if ( nLevel
> nIdLevel
)
134 if ( bChild
&& bChildWithText
)
136 OString
sError("ResId after child definition");
137 yyerror(sError
.getStr());
141 if ( sId
.getLength() > 255 )
143 YYWarning( "LocalId > 255 chars, truncating..." );
144 sId
= sId
.copy(0, 255).trim();
160 static sal_Int32
lcl_countOccurrences(const OString
& text
, char c
)
163 for (sal_Int32 i
= 0;; ++i
) {
164 i
= text
.indexOf(c
, i
);
175 Export::Export(const OString
&rOutput
)
177 bDefine( sal_False
),
178 bNextMustBeDefineEOL( sal_False
),
186 bReadOver( sal_False
),
187 bDontWriteOutput( sal_False
),
188 sFilename( global::inputPathname
),
189 sLanguages( OString() ),
190 pParseQueue( new ParserQueue( *this ) )
192 aOutput
.mPo
= new PoOfstream( rOutput
, PoOfstream::APP
);
193 if (!aOutput
.mPo
->isOpen()) {
194 fprintf(stderr
, "ERROR : Can't open file %s\n", rOutput
.getStr());
200 const OString
&rMergeSource
, const OString
&rOutput
,
201 const OString
&rLanguage
, bool bUTF8BOM
)
203 bDefine( sal_False
),
204 bNextMustBeDefineEOL( sal_False
),
210 bMergeMode( sal_True
),
211 sMergeSrc( rMergeSource
),
213 bReadOver( sal_False
),
214 bDontWriteOutput( sal_False
),
215 sFilename( global::inputPathname
),
216 sLanguages( rLanguage
),
217 pParseQueue( new ParserQueue( *this ) )
219 aOutput
.mSimple
= new std::ofstream();
220 aOutput
.mSimple
->open(rOutput
.getStr(), std::ios_base::out
| std::ios_base::trunc
);
222 if ( bUTF8BOM
) WriteUTF8ByteOrderMarkToOutput();
227 // resets the internal status, used before parseing another file
229 bNextMustBeDefineEOL
= sal_False
;
232 m_sListLang
= OString();
234 for ( size_t i
= 0, n
= aResStack
.size(); i
< n
; ++i
)
235 delete aResStack
[ i
];
245 aOutput
.mSimple
->close();
246 delete aOutput
.mSimple
;
250 aOutput
.mPo
->close();
253 for ( size_t i
= 0, n
= aResStack
.size(); i
< n
; ++i
)
254 delete aResStack
[ i
];
258 if ( !pMergeDataFile
)
259 pMergeDataFile
= new MergeDataFile(sMergeSrc
, global::inputPathname
, false);
261 delete pMergeDataFile
;
265 int Export::Execute( int nToken
, const char * pToken
)
268 OString
sToken( pToken
);
269 OString
sOrig( sToken
);
270 sal_Bool bWriteToMerged
= bMergeMode
;
272 if ( nToken
== CONDITION
)
274 OString
sTestToken(pToken
);
275 sTestToken
= sTestToken
.replaceAll("\t", OString()).
276 replaceAll(" ", OString());
277 if (( !bReadOver
) && ( sTestToken
.startsWith("#ifndef__RSC_PARSER")))
278 bReadOver
= sal_True
;
279 else if (( bReadOver
) && ( sTestToken
.startsWith("#endif") ))
280 bReadOver
= sal_False
;
282 if ((( nToken
< FILTER_LEVEL
) || ( bReadOver
)) &&
283 (!(( bNextMustBeDefineEOL
) && ( sOrig
== "\n" )))) {
284 // this tokens are not mandatory for parsing, so ignore them ...
286 WriteToMerged( sOrig
, false ); // ... or write them directly to dest.
290 ResData
*pResData
= NULL
;
292 // res. exists at cur. level
293 pResData
= ( (nLevel
-1) < aResStack
.size() ) ? aResStack
[ nLevel
-1 ] : NULL
;
295 else if (( nToken
!= RESOURCE
) &&
296 ( nToken
!= RESOURCEEXPR
) &&
297 ( nToken
!= SMALRESOURCE
) &&
298 ( nToken
!= LEVELUP
) &&
299 ( nToken
!= NORMDEFINE
) &&
300 ( nToken
!= RSCDEFINE
) &&
301 ( nToken
!= CONDITION
) &&
302 ( nToken
!= PRAGMA
))
304 // no res. exists at cur. level so return
306 WriteToMerged( sOrig
, false );
309 // #define NO_LOCALIZE_EXPORT
312 WriteToMerged( sOrig
, false );
319 if (( nToken
!= EMPTYLINE
) && ( nToken
!= LEVELDOWN
) && ( nToken
!= LEVELUP
)) {
320 // cur. res. defined in macro
321 if ( bNextMustBeDefineEOL
) {
322 if ( nToken
!= RSCDEFINELEND
) {
323 // end of macro found, so destroy res.
325 Execute( LEVELDOWN
, "" );
326 bNextMustBeDefineEOL
= sal_False
;
329 // next line also in macro definition
330 bNextMustBeDefineEOL
= sal_False
;
332 WriteToMerged( sOrig
, false );
339 sal_Bool bExecuteDown
= sal_False
;
340 if ( nToken
!= LEVELDOWN
) {
341 sal_uInt16 nOpen
= 0;
342 sal_uInt16 nClose
= 0;
343 sal_Bool bReadOver1
= sal_False
;
345 for ( i
= 0; i
< sToken
.getLength(); i
++ ) {
346 if ( sToken
[i
] == '"' )
347 bReadOver1
= !bReadOver1
;
348 if ( !bReadOver1
&& ( sToken
[i
] == '{' ))
352 bReadOver1
= sal_False
;
353 for ( i
= 0; i
< sToken
.getLength(); i
++ ) {
354 if ( sToken
[i
] == '"' )
355 bReadOver1
= !bReadOver1
;
356 if ( !bReadOver1
&& ( sToken
[i
] == '}' ))
360 if ( nOpen
< nClose
)
361 bExecuteDown
= sal_True
;
366 sToken
= sToken
.replace('\r', ' ').replace('\t', ' ');
369 sToken
= sToken
.replaceFirst(" ", " ", &n
);
374 if( sToken
.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("#define NO_LOCALIZE_EXPORT")) ){
379 WriteToMerged( sOrig
, false );
385 bDefine
= sal_True
; // res. defined in macro
389 bDontWriteOutput
= sal_False
;
390 if ( nToken
!= RSCDEFINE
)
391 bNextMustBeDefineEOL
= sal_False
;
392 // this is the beginning of a new res.
395 aResStack
[ nLevel
- 2 ]->bChild
= sal_True
;
398 // create new instance for this res. and fill mandatory fields
400 pResData
= new ResData( FullId() , sFilename
);
401 aResStack
.push_back( pResData
);
402 sToken
= sToken
.replaceAll("\n", OString()).
403 replaceAll("\r", OString()).
404 replaceAll("{", OString()).replace('\t', ' ');
405 sToken
= sToken
.trim();
406 OString sTLower
= sToken
.getToken(0, ' ').toAsciiLowerCase();
407 pResData
->sResTyp
= sTLower
;
408 OString
sId( sToken
.copy( pResData
->sResTyp
.getLength() + 1 ));
410 if ( sId
.indexOf( '#' ) != -1 )
412 // between ResTyp, Id and paranthes is a precomp. condition
415 sId
= sId
.getToken(0, '#', n
);
416 sCondition
+= sId
.getToken(0, '#', n
);
418 sId
= sId
.getToken(0, '/');
420 sId
= sId
.replaceAll("\t", OString());
421 pResData
->SetId( sId
, ID_LEVEL_IDENTIFIER
);
422 if (!sCondition
.isEmpty())
424 Execute( CONDITION
, ""); // execute the precomp. condition
429 bDontWriteOutput
= sal_False
;
430 // this is the beginning of a new res.
431 bNextMustBeDefineEOL
= sal_False
;
434 aResStack
[ nLevel
- 2 ]->bChild
= sal_True
;
437 // create new instance for this res. and fill mandatory fields
439 pResData
= new ResData( FullId() , sFilename
);
440 aResStack
.push_back( pResData
);
441 sToken
= sToken
.replaceAll("\n", OString()).
442 replaceAll("\r", OString()).
443 replaceAll("{", OString()).
444 replaceAll("\t", OString()).
445 replaceAll(" ", OString()).
446 replaceAll("\\", OString()).toAsciiLowerCase();
447 pResData
->sResTyp
= sToken
;
457 bDontWriteOutput
= sal_False
;
460 sLowerTyp
= "unknown";
463 aResStack
[ nLevel
- 2 ]->bChild
= sal_True
;
466 ResData
*pNewData
= new ResData( FullId() , sFilename
);
467 pNewData
->sResTyp
= sLowerTyp
;
468 aResStack
.push_back( pNewData
);
474 bDontWriteOutput
= sal_False
;
476 if ( bDefine
&& (nLevel
== 1 )) {
478 bNextMustBeDefineEOL
= sal_False
;
480 WriteData( pResData
);
481 ResStack::iterator it
= aResStack
.begin();
482 ::std::advance( it
, nLevel
-1 );
484 aResStack
.erase( it
);
490 bNextMustBeDefineEOL
= sal_True
;
501 bDontWriteOutput
= sal_False
;
502 // interpret different types of assignement
504 OString sKey
= sToken
.getToken(0, '=', n
).
505 replaceAll(" ", OString()).
506 replaceAll("\t", OString());
507 OString sValue
= sToken
.getToken(0, '=', n
);
508 CleanValue( sValue
);
509 sKey
= sKey
.toAsciiUpperCase();
510 if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("IDENTIFIER")))
513 sValue
.replaceAll("\t", OString()).
514 replaceAll(" ", OString()));
515 pResData
->SetId(sId
, ID_LEVEL_IDENTIFIER
);
517 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("HELPID")))
519 pResData
->sHelpId
= sValue
;
521 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("STRINGLIST")))
523 pResData
->bList
= sal_True
;
525 m_sListLang
= SOURCE_LANGUAGE
;
529 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("FILTERLIST")))
531 pResData
->bList
= sal_True
;
533 m_sListLang
= SOURCE_LANGUAGE
;
537 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("UIENTRIES")))
539 pResData
->bList
= sal_True
;
540 nList
= LIST_UIENTRIES
;
541 m_sListLang
= SOURCE_LANGUAGE
;
545 if (sToken
.indexOf( '{' ) != -1
546 && (lcl_countOccurrences(sToken
, '{')
547 > lcl_countOccurrences(sToken
, '}')))
549 Parse( LEVELUP
, "" );
556 bDontWriteOutput
= sal_False
;
558 sToken
.replaceAll(" ", OString()).toAsciiLowerCase());
559 sal_Int32 nPos
= sTmpToken
.indexOf("[en-us]=");
562 sTmpToken
.copy(0 , nPos
).replaceAll(" ", OString()).
563 replaceAll("\t", OString()));
564 OString sValue
= sToken
.getToken(1, '=');
565 CleanValue( sValue
);
566 sKey
= sKey
.toAsciiUpperCase();
567 if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("STRINGLIST")))
569 pResData
->bList
= sal_True
;
571 m_sListLang
= SOURCE_LANGUAGE
;
575 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("FILTERLIST")))
577 pResData
->bList
= sal_True
;
579 m_sListLang
= SOURCE_LANGUAGE
;
583 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("PAIREDLIST")))
585 pResData
->bList
= sal_True
;
587 m_sListLang
= SOURCE_LANGUAGE
;
591 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("ITEMLIST")))
593 pResData
->bList
= sal_True
;
595 m_sListLang
= SOURCE_LANGUAGE
;
599 else if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("UIENTRIES")))
601 pResData
->bList
= sal_True
;
602 nList
= LIST_UIENTRIES
;
603 m_sListLang
= SOURCE_LANGUAGE
;
613 // this is an entry for a String- or FilterList
617 OString
sEntry(sToken
.getToken(1, '"', n
));
618 if ( lcl_countOccurrences(sToken
, '"') > 2 )
620 if ( sEntry
== "\\\"" )
622 InsertListEntry( sEntry
, sOrig
);
628 bDontWriteOutput
= sal_False
;
631 CutComment( sToken
);
633 // this is a text line!!!
634 OString
t(sToken
.getToken(0, '='));
636 t
.getToken(0, '[').replaceAll(" ", OString()).
637 replaceAll("\t", OString()));
638 OString
sText( GetText( sToken
, nToken
));
640 if ( sToken
.getToken(0, '=').indexOf('[') != -1 )
642 sLang
= sToken
.getToken(0, '=').getToken(1, '[').
646 OString sLangIndex
= sLang
;
647 OString sOrigKey
= sKey
;
648 if ( !sText
.isEmpty() && !sLang
.isEmpty() )
650 sKey
= sKey
.toAsciiUpperCase();
651 if (sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("TEXT")) ||
652 sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("MESSAGE")) ||
653 sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("CUSTOMUNITTEXT")) ||
654 sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("SLOTNAME")) ||
655 sKey
.equalsL(RTL_CONSTASCII_STRINGPARAM("UINAME")))
658 if ( sLangIndex
.equalsIgnoreAsciiCase("en-US") )
659 pResData
->SetId( sText
, ID_LEVEL_TEXT
);
661 pResData
->bText
= sal_True
;
662 pResData
->sTextTyp
= sOrigKey
;
665 if (!pResData
->sText
[ sLangIndex
].isEmpty())
667 OStringBuffer
sError("Language ");
668 sError
.append(sLangIndex
);
669 sError
.append("defined twice");
670 yyerror(sError
.getStr());
672 pResData
->sText
[ sLangIndex
] = sText
;
675 else if ( sKey
== "HELPTEXT" ) {
677 pResData
->bHelpText
= sal_True
;
680 if (!pResData
->sHelpText
[ sLangIndex
].isEmpty())
682 OStringBuffer
sError("Language ");
683 sError
.append(sLangIndex
);
684 sError
.append(" defined twice");
685 YYWarning(sError
.getStr());
687 pResData
->sHelpText
[ sLangIndex
] = sText
;
690 else if ( sKey
== "QUICKHELPTEXT" ) {
692 pResData
->bQuickHelpText
= sal_True
;
695 if (!pResData
->sQuickHelpText
[ sLangIndex
].isEmpty())
697 OStringBuffer
sError("Language ");
698 sError
.append(sLangIndex
);
699 sError
.append(" defined twice");
700 YYWarning(sError
.getStr());
702 pResData
->sQuickHelpText
[ sLangIndex
] = sText
;
705 else if ( sKey
== "TITLE" ) {
707 pResData
->bTitle
= sal_True
;
710 if ( !pResData
->sTitle
[ sLangIndex
].isEmpty())
712 OStringBuffer
sError("Language ");
713 sError
.append(sLangIndex
);
714 sError
.append(" defined twice");
715 YYWarning(sError
.getStr());
717 pResData
->sTitle
[ sLangIndex
] = sText
;
720 else if ( sKey
== "ACCESSPATH" ) {
721 pResData
->SetId( sText
, ID_LEVEL_ACCESSPATH
);
723 else if ( sKey
== "FIELDNAME" ) {
724 pResData
->SetId( sText
, ID_LEVEL_FIELDNAME
);
730 bDontWriteOutput
= sal_True
;
735 bDontWriteOutput
= sal_False
;
739 bDontWriteOutput
= sal_False
;
742 bDontWriteOutput
= sal_False
;
744 WriteData( pResData
, sal_True
);
749 bDontWriteOutput
= sal_False
;
751 bNextMustBeDefineEOL
= sal_False
;
754 Parse( LEVELDOWN
, "" );
759 bDontWriteOutput
= sal_False
;
760 fprintf(stderr
, "ERROR: archaic PRAGMA %s\n", sToken
.getStr());
765 bDontWriteOutput
= sal_True
;
768 if ( bWriteToMerged
) {
769 // the current token must be written to dest. without merging
771 if( bDefine
&& sOrig
.getLength() > 2 ){
772 for( sal_uInt16 n
= 0 ; n
< sOrig
.getLength() ; n
++ ){
773 if( sOrig
[n
] == '\n' && sOrig
[n
-1] != '\\'){
774 sOrig
= sOrig
.replaceAt(n
++, 0, "\\");
778 WriteToMerged( sOrig
, false);
781 if ( bExecuteDown
) {
782 Parse( LEVELDOWN
, "" );
788 void Export::CutComment( OString
&rText
)
790 if (rText
.indexOf("//") != -1) {
791 OString
sWork(rText
.replaceAll("\\\"", "XX"));
793 for (sal_Int32 i
= 0; i
< sWork
.getLength() - 1; ++i
) {
794 if (sWork
[i
] == '"') {
796 } else if (sWork
[i
] == '/' && !bInner
&& sWork
[i
+ 1] == '/' ) {
797 rText
= rText
.copy(0, i
);
804 sal_Bool
Export::WriteData( ResData
*pResData
, sal_Bool bCreateNew
)
807 MergeRest( pResData
);
811 // mandatory to export: en-US
813 if (( !pResData
->sText
[ SOURCE_LANGUAGE
].isEmpty())
815 ( !pResData
->sHelpText
[ SOURCE_LANGUAGE
].isEmpty())
817 ( !pResData
->sQuickHelpText
[ SOURCE_LANGUAGE
].isEmpty())
819 ( !pResData
->sTitle
[ SOURCE_LANGUAGE
].isEmpty()))
822 OString sGID
= pResData
->sGId
;
825 sGID
= pResData
->sId
;
827 sLID
= pResData
->sId
;
834 sXText
= pResData
->sText
[ SOURCE_LANGUAGE
];
835 if (!pResData
->sText
[ X_COMMENT
].isEmpty())
836 sXHText
= pResData
->sText
[ X_COMMENT
];
838 sXHText
= pResData
->sHelpText
[ SOURCE_LANGUAGE
];
839 sXQHText
= pResData
->sQuickHelpText
[ SOURCE_LANGUAGE
];
840 sXTitle
= pResData
->sTitle
[ SOURCE_LANGUAGE
];
842 if( !sXText
.isEmpty() )
844 ConvertExportContent(sXText
);
845 ConvertExportContent(sXHText
);
846 common::writePoEntry(
847 "Transex3", *aOutput
.mPo
, global::inputPathname
,
848 pResData
->sResTyp
, sGID
, sLID
, sXHText
, sXText
);
850 if( !sXQHText
.isEmpty() )
852 ConvertExportContent(sXQHText
);
853 common::writePoEntry(
854 "Transex3", *aOutput
.mPo
, global::inputPathname
, pResData
->sResTyp
,
855 sGID
, sLID
, OString(), sXQHText
, PoEntry::TQUICKHELPTEXT
);
857 if( !sXTitle
.isEmpty() )
859 ConvertExportContent(sXTitle
);
860 common::writePoEntry(
861 "Transex3", *aOutput
.mPo
, global::inputPathname
, pResData
->sResTyp
,
862 sGID
, sLID
, OString(), sXTitle
, PoEntry::TTITLE
);
866 pResData
->sText
[ SOURCE_LANGUAGE
] = "";
867 pResData
->sHelpText
[ SOURCE_LANGUAGE
] = "";
868 pResData
->sQuickHelpText
[ SOURCE_LANGUAGE
]= "";
869 pResData
->sTitle
[ SOURCE_LANGUAGE
] = "";
872 if ( pResData
->pStringList
) {
873 OString
sList( "stringlist" );
874 WriteExportList( pResData
, pResData
->pStringList
, sList
, bCreateNew
);
876 pResData
->pStringList
= 0;
878 if ( pResData
->pFilterList
) {
879 OString
sList( "filterlist" );
880 WriteExportList( pResData
, pResData
->pFilterList
, sList
, bCreateNew
);
882 pResData
->pFilterList
= 0;
884 if ( pResData
->pItemList
) {
885 OString
sList( "itemlist" );
886 WriteExportList( pResData
, pResData
->pItemList
, sList
, bCreateNew
);
888 pResData
->pItemList
= 0;
890 if ( pResData
->pPairedList
) {
891 OString
sList( "pairedlist" );
892 WriteExportList( pResData
, pResData
->pPairedList
, sList
, bCreateNew
);
894 pResData
->pPairedList
= 0;
896 if ( pResData
->pUIEntries
) {
897 OString
sList( "uientries" );
898 WriteExportList( pResData
, pResData
->pUIEntries
, sList
, bCreateNew
);
900 pResData
->pUIEntries
= 0;
905 OString
Export::GetPairedListID(const OString
& rText
)
907 // < "STRING" ; IDENTIFIER ; > ;
908 return rText
.getToken(1, ';').toAsciiUpperCase().replace('\t', ' ').trim();
911 OString
Export::GetPairedListString(const OString
& rText
)
913 // < "STRING" ; IDENTIFIER ; > ;
914 OString
sString(rText
.getToken(0, ';').replace('\t', ' '));
915 sString
= sString
.trim();
916 OString
s1(sString
.copy(sString
.indexOf('"') + 1));
917 sString
= s1
.copy(0, s1
.lastIndexOf('"'));
918 return sString
.trim();
921 OString
Export::StripList(const OString
& rText
)
923 OString s1
= rText
.copy( rText
.indexOf('\"') + 1);
924 return s1
.copy( 0 , s1
.lastIndexOf('\"'));
927 sal_Bool
Export::WriteExportList(ResData
*pResData
, ExportList
*pExportList
,
928 const OString
&rTyp
, sal_Bool bCreateNew
)
930 OString
sGID(pResData
->sGId
);
932 sGID
= pResData
->sId
;
935 sGID
+= pResData
->sId
;
936 while (sGID
.endsWith(".")) {
937 sGID
= sGID
.copy(0, sGID
.getLength() - 1);
941 for ( size_t i
= 0; pExportList
!= NULL
&& i
< pExportList
->size(); i
++ )
943 ExportListEntry
*pEntry
= (*pExportList
)[ i
];
946 OString
sText((*pEntry
)[ SOURCE_LANGUAGE
] );
948 // Strip PairList Line String
949 if (rTyp
.equalsIgnoreAsciiCase("pairedlist"))
951 sLID
= GetPairedListID( sText
);
952 sText
= GetPairedListString( sText
);
956 sLID
= OString::number(i
+ 1);
957 sText
= StripList( sText
);
958 if( sText
== "\\\"" )
961 ConvertExportContent(sText
);
962 common::writePoEntry(
963 "Transex3", *aOutput
.mPo
, global::inputPathname
,
964 rTyp
, sGID
, sLID
, OString(), sText
);
975 OString
Export::FullId()
980 sFull
.append(aResStack
[ 0 ]->sId
);
981 for ( size_t i
= 1; i
< nLevel
- 1; ++i
)
983 OString sToAdd
= aResStack
[ i
]->sId
;
984 if (!sToAdd
.isEmpty())
985 sFull
.append('.').append(sToAdd
);
988 if (sFull
.getLength() > 255)
990 OString
sError("GroupId > 255 chars");
991 printf("GroupID = %s\n", sFull
.getStr());
992 yyerror(sError
.getStr());
995 return sFull
.makeStringAndClear();
998 void Export::InsertListEntry(const OString
&rText
, const OString
&rLine
)
1000 ResData
*pResData
= ( nLevel
-1 < aResStack
.size() ) ? aResStack
[ nLevel
-1 ] : NULL
;
1002 ExportList
*pList
= NULL
;
1003 if ( nList
== LIST_STRING
) {
1004 pList
= pResData
->pStringList
;
1006 pResData
->pStringList
= new ExportList();
1007 pList
= pResData
->pStringList
;
1011 else if ( nList
== LIST_FILTER
) {
1012 pList
= pResData
->pFilterList
;
1014 pResData
->pFilterList
= new ExportList();
1015 pList
= pResData
->pFilterList
;
1019 else if ( nList
== LIST_ITEM
) {
1020 pList
= pResData
->pItemList
;
1022 pResData
->pItemList
= new ExportList();
1023 pList
= pResData
->pItemList
;
1027 else if ( nList
== LIST_PAIRED
) {
1028 pList
= pResData
->pPairedList
;
1030 pResData
->pPairedList
= new ExportList();
1031 pList
= pResData
->pPairedList
;
1035 else if ( nList
== LIST_UIENTRIES
) {
1036 pList
= pResData
->pUIEntries
;
1038 pResData
->pUIEntries
= new ExportList();
1039 pList
= pResData
->pUIEntries
;
1046 if ( nListIndex
+ 1 > pList
->size())
1048 ExportListEntry
*pNew
= new ExportListEntry();
1049 (*pNew
)[LIST_REFID
] = OString::number(REFID_NONE
);
1050 pList
->push_back(pNew
);
1052 ExportListEntry
*pCurEntry
= (*pList
)[ nListIndex
];
1054 // For paired list use the line to set proper lid
1055 if( nList
== LIST_PAIRED
){
1056 (*pCurEntry
)[ m_sListLang
] = rLine
;
1058 (*pCurEntry
)[ m_sListLang
] = rText
;
1060 if ( m_sListLang
.equalsIgnoreAsciiCase("en-US") ) {
1061 (*pCurEntry
)[ SOURCE_LANGUAGE
] = rLine
;
1063 pList
->NewSourceLanguageListEntry();
1069 void Export::CleanValue( OString
&rValue
)
1071 while ( !rValue
.isEmpty()) {
1072 if (( rValue
[0] == ' ' ) || ( rValue
[0] == '\t' ))
1073 rValue
= rValue
.copy( 1 );
1078 if ( !rValue
.isEmpty()) {
1079 for ( sal_Int32 i
= rValue
.getLength() - 1; i
> 0; i
-- ) {
1080 if (( rValue
[i
] == ' ' ) || ( rValue
[i
] == '\t' ) ||
1081 ( rValue
[i
] == '\n' ) || ( rValue
[i
] == ';' ) ||
1082 ( rValue
[i
] == '{' ) || ( rValue
[i
] == '\\' ) ||
1083 ( rValue
[i
] == '\r' ))
1084 rValue
= rValue
.copy(0, i
);
1091 #define TXT_STATE_TEXT 0x001
1092 #define TXT_STATE_MACRO 0x002
1094 OString
Export::GetText(const OString
&rSource
, int nToken
)
1102 OString
sTmp(rSource
.copy(rSource
.indexOf('=')));
1104 sTmp
= sTmp
.replaceAll("\n", OString()).
1105 replaceAll("\r", OString()).
1106 replaceAll("\\\\\"", "-=<[BSlashBSlashHKom]>=-\"").
1107 replaceAll("\\\"", "-=<[Hochkomma]>=-").
1108 replaceAll("\\\x7f", "-=<[0x7F]>=-").
1109 replaceAll("\\0x7F", "-=<[0x7F]>=-");
1111 sal_uInt16 nState
= TXT_STATE_TEXT
;
1112 for (sal_Int32 i
= 1; i
<= lcl_countOccurrences(sTmp
, '"'); ++i
)
1114 OString
sToken(sTmp
.getToken(i
, '"'));
1115 if (!sToken
.isEmpty()) {
1116 if ( nState
== TXT_STATE_TEXT
) {
1118 nState
= TXT_STATE_MACRO
;
1121 sToken
= sToken
.replace('\t', ' ');
1124 sToken
= sToken
.replaceFirst(" ", " ", &n
);
1129 sToken
= sToken
.trim();
1130 if (!sToken
.isEmpty()) {
1135 nState
= TXT_STATE_TEXT
;
1140 sReturn
= sReturn
.replaceAll("-=<[0x7F]>=-", "\x7f").
1141 replaceAll("-=<[Hochkomma]>=-", "\"").
1142 replaceAll("-=<[BSlashBSlashHKom]>=-", "\\\\").
1143 replaceAll("\\\\", "-=<[BSlashBSlash]>=-").
1144 replaceAll("-=<[BSlashBSlash]>=-", "\\");
1151 void Export::WriteToMerged(const OString
&rText
, bool bSDFContent
)
1153 OString
sText(rText
);
1156 sText
= sText
.replaceFirst(" \n", "\n", &n
);
1161 if (pParseQueue
->bNextIsM
&& bSDFContent
&& sText
.getLength() > 2) {
1162 for (sal_Int32 n
= 0; n
< sText
.getLength(); ++n
) {
1163 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
1164 sText
= sText
.replaceAt(n
++, 0, "\\");
1167 } else if (pParseQueue
->bLastWasM
&& sText
.getLength() > 2) {
1168 for (sal_Int32 n
= 0; n
< sText
.getLength(); ++n
) {
1169 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
1170 sText
= sText
.replaceAt(n
++, 0, "\\");
1172 if (sText
[n
] == '\n') {
1173 pParseQueue
->bMflag
= true;
1176 } else if (pParseQueue
->bCurrentIsM
&& bSDFContent
&& sText
.getLength() > 2)
1178 for (sal_Int32 n
= 0; n
< sText
.getLength(); ++n
) {
1179 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
1180 sText
= sText
.replaceAt(n
++, 0, "\\");
1181 pParseQueue
->bMflag
= true;
1184 } else if (pParseQueue
->bMflag
) {
1185 for (sal_Int32 n
= 1; n
< sText
.getLength(); ++n
) {
1186 if (sText
[n
] == '\n' && sText
[n
- 1] != '\\') {
1187 sText
= sText
.replaceAt(n
++, 0, "\\");
1190 } for (sal_Int32 i
= 0; i
< sText
.getLength(); ++i
) {
1191 if (sText
[i
] == '\n') {
1192 *aOutput
.mSimple
<< '\n';
1194 char cChar
= sText
[i
];
1195 *aOutput
.mSimple
<< cChar
;
1200 void Export::ConvertMergeContent( OString
&rText
)
1202 rText
= rText
.replaceAll("\\\'","\'"); // Temporary: until PO files contain escaped single quotes
1203 // (Maybe next PO update solve this)
1206 rText
.replaceAll("\x7f","\\0x7F"),
1207 "\n""\t""\\""\"","\\n""\\t""\\\\""\\\"");
1209 rText
= "\"" + rText
+ "\"";
1212 void Export::ConvertExportContent( OString
& rText
)
1214 rText
= helper::unEscapeAll(rText
,"\\n""\\t""\\\\""\\\"","\n""\t""\\""\"");
1217 bool Export::GetAllMergeEntrysOfList(ResData
*pResData
, std::vector
<MergeEntrys
*>& o_vMergeEntrys
, ExportList
*& o_pList
)
1219 o_vMergeEntrys
.clear();
1222 if (!pResData
->sGId
.isEmpty())
1223 pResData
->sGId
= pResData
->sGId
+ OString('.');
1224 pResData
->sGId
= pResData
->sGId
+ pResData
->sId
;
1226 // Find out the type of List
1227 MergeEntrys
* pEntrysOfFirstItem
= 0;
1228 sal_uInt16 nType
= LIST_STRING
;
1229 bool bPairedList
= false;
1230 while( !pEntrysOfFirstItem
&& nType
<= LIST_UIENTRIES
)
1234 case LIST_STRING
: pResData
->sResTyp
= "stringlist"; o_pList
= pResData
->pStringList
; bPairedList
= false; break;
1235 case LIST_FILTER
: pResData
->sResTyp
= "filterlist"; o_pList
= pResData
->pFilterList
; bPairedList
= false; break;
1236 case LIST_UIENTRIES
: pResData
->sResTyp
= "uientries"; o_pList
= pResData
->pUIEntries
;bPairedList
= false; break;
1237 case LIST_ITEM
: pResData
->sResTyp
= "itemlist"; o_pList
= pResData
->pItemList
; bPairedList
= false; break;
1238 case LIST_PAIRED
: pResData
->sResTyp
= "pairedlist"; o_pList
= pResData
->pPairedList
; bPairedList
= true; break;
1241 // Set matching pairedlist identifier
1242 if( bPairedList
&& pResData
->pPairedList
)
1244 ExportListEntry
* pListE
= ( ExportListEntry
* ) (*pResData
->pPairedList
)[ 0 ];
1245 pResData
->sId
= GetPairedListID ( (*pListE
)[ SOURCE_LANGUAGE
] );
1248 pResData
->sId
= "1";
1250 pEntrysOfFirstItem
= pMergeDataFile
->GetMergeEntrys( pResData
);
1254 if( !pEntrysOfFirstItem
)
1262 sal_uInt16 nMaxIndex
= 0;
1265 nMaxIndex
= o_pList
->GetSourceLanguageListEntryCount();
1268 * Check whether count of listentries match with count
1269 * of translated items. If not than write origin items
1270 * to the list to avoid mixed translations
1271 * (exclude pairedlist)
1275 MergeEntrys
* pEntrys
;
1276 // MergeData contains longer list
1277 pResData
->sId
= OString::number(nMaxIndex
+1);
1278 pEntrys
= pMergeDataFile
->GetMergeEntrys( pResData
);
1281 // MergeData contains shorter list
1282 pResData
->sId
= OString::number(nMaxIndex
);
1283 pEntrys
= pMergeDataFile
->GetMergeEntrys( pResData
);
1286 pResData
->sId
= "1";
1289 o_vMergeEntrys
.push_back(pEntrysOfFirstItem
);
1291 for( sal_uInt16 nLIndex
= 2; nLIndex
<= nMaxIndex
; ++nLIndex
)
1293 // Set matching pairedlist identifier
1296 ExportListEntry
* pListE
= ( ExportListEntry
* )(*pResData
->pPairedList
)[ ( nLIndex
) -1 ];
1299 pResData
->sId
= GetPairedListID ( (*pListE
)[ SOURCE_LANGUAGE
] );
1303 pResData
->sId
= OString::number(nLIndex
);
1305 MergeEntrys
* pEntrys
= pMergeDataFile
->GetMergeEntrys( pResData
);
1306 o_vMergeEntrys
.push_back(pEntrys
);
1311 void Export::ResData2Output( MergeEntrys
*pEntry
, sal_uInt16 nType
, const OString
& rTextType
)
1313 sal_Bool bAddSemicolon
= sal_False
;
1314 sal_Bool bFirst
= sal_True
;
1317 for( unsigned int n
= 0; n
< aLanguages
.size(); n
++ ){
1318 sCur
= aLanguages
[ n
];
1321 sal_Bool bText
= pEntry
->GetText( sText
, nType
, sCur
, sal_True
);
1322 if ( bText
&& !sText
.isEmpty() ) {
1324 if ( bNextMustBeDefineEOL
) {
1326 sOutput
+= "\t\\\n";
1328 sOutput
+= ";\t\\\n";
1333 sOutput
+= rTextType
;
1335 if ( !sCur
.equalsIgnoreAsciiCase("en-US") ) {
1341 ConvertMergeContent( sText
);
1346 else if ( !bNextMustBeDefineEOL
)
1349 bAddSemicolon
= sal_True
;
1350 for ( sal_uInt16 j
= 1; j
< nLevel
; j
++ )
1352 WriteToMerged( sOutput
, true );
1357 if ( bAddSemicolon
) {
1358 OString
sOutput( ";" );
1359 WriteToMerged( sOutput
, false );
1363 void Export::MergeRest( ResData
*pResData
, sal_uInt16 nMode
)
1365 if ( !pMergeDataFile
){
1366 pMergeDataFile
= new MergeDataFile( sMergeSrc
, global::inputPathname
, false );
1367 aLanguages
= pMergeDataFile
->GetLanguages();
1371 case MERGE_MODE_NORMAL
: {
1372 MergeEntrys
*pEntry
= 0;
1373 if( pResData
->bText
|| pResData
->bQuickHelpText
|| pResData
->bTitle
)
1374 pEntry
= pMergeDataFile
->GetMergeEntrys( pResData
);
1377 if ( pResData
->bText
)
1378 ResData2Output( pEntry
, STRING_TYP_TEXT
, pResData
->sTextTyp
);
1380 if ( pResData
->bQuickHelpText
)
1381 ResData2Output( pEntry
, STRING_TYP_QUICKHELPTEXT
, OString("QuickHelpText") );
1383 if ( pResData
->bTitle
)
1384 ResData2Output( pEntry
, STRING_TYP_TITLE
, OString("Title") );
1389 if ( pResData
->bList
) {
1390 OString sOldId
= pResData
->sId
;
1391 OString sOldGId
= pResData
->sGId
;
1392 OString sOldTyp
= pResData
->sResTyp
;
1393 sal_uInt16 nOldListTyp
= nList
;
1396 for ( sal_uInt16 i
= 1; i
< nLevel
-1; i
++ )
1399 std::vector
<MergeEntrys
*> vMergeEntryVector
;
1400 ExportList
* pList
= 0;
1401 bool bTranslateList
= GetAllMergeEntrysOfList(pResData
, vMergeEntryVector
, pList
);
1406 for( unsigned int n
= 0; n
< aLanguages
.size(); n
++ )
1408 sCur
= aLanguages
[ n
];
1410 sal_uInt16 nLIndex
= 0;
1411 sal_uInt16 nMaxIndex
= pList
->GetSourceLanguageListEntryCount();
1412 while( nLIndex
< nMaxIndex
)
1416 OStringBuffer sHead
;
1417 if ( bNextMustBeDefineEOL
)
1418 sHead
.append("\\\n\t");
1419 sHead
.append(sSpace
);
1423 sHead
.append("StringList ");
1426 sHead
.append("FilterList ");
1429 sHead
.append("ItemList ");
1432 sHead
.append("PairedList ");
1434 case LIST_UIENTRIES
:
1435 sHead
.append("UIEntries ");
1440 sHead
.append(" ] ");
1441 if ( bDefine
|| bNextMustBeDefineEOL
)
1443 sHead
.append("= \\\n");
1444 sHead
.append(sSpace
);
1445 sHead
.append("\t{\\\n\t");
1449 sHead
.append("= \n");
1450 sHead
.append(sSpace
);
1451 sHead
.append("\t{\n\t");
1453 WriteToMerged(sHead
.makeStringAndClear() , true);
1456 if ( pList
&& (*pList
)[ nLIndex
] )
1457 sLine
= ( *(*pList
)[ nLIndex
])[ SOURCE_LANGUAGE
];
1459 if ( sLine
.indexOf( '>' ) != -1 ) {
1460 if (( nList
!= LIST_UIENTRIES
) &&
1461 (( sLine
.indexOf( '{' ) == -1 ) ||
1462 ( sLine
.indexOf( '{' ) >= sLine
.indexOf( '"' ))) &&
1463 (( sLine
.indexOf( '<' ) == -1 ) ||
1464 ( sLine
.indexOf( '<' ) >= sLine
.indexOf( '"' ))))
1466 sLine
= sLine
.replaceFirst("\"", "< \"" );
1470 if( bTranslateList
&& nLIndex
< vMergeEntryVector
.size() && vMergeEntryVector
[nLIndex
] )
1474 bText
= vMergeEntryVector
[nLIndex
]->GetText( sText
, STRING_TYP_TEXT
, sCur
, sal_True
);
1475 if ( bText
&& !sText
.isEmpty() )
1477 ConvertMergeContent( sText
);
1478 OString sPre
= sLine
.copy( 0 , sLine
.indexOf('"') );
1479 OString sPost
= sLine
.copy( sLine
.lastIndexOf('"') + 1 );
1480 sLine
= sPre
+ sText
+ sPost
;
1484 OString
sText1( "\t" );
1486 if ( bDefine
|| bNextMustBeDefineEOL
)
1492 WriteToMerged( sText1
,true );
1495 if ( nLIndex
> 0 ) {
1497 if (!sSpace
.isEmpty()) {
1498 sFooter
= sSpace
.copy(1);
1500 if ( bNextMustBeDefineEOL
)
1502 else if ( !bDefine
)
1503 sFooter
+= "};\n\t";
1506 WriteToMerged( sFooter
,true );
1511 pResData
->sId
= sOldId
;
1512 pResData
->sGId
= sOldGId
;
1513 pResData
->sResTyp
= sOldTyp
;
1514 nList
= nOldListTyp
;
1518 case MERGE_MODE_LIST
: {
1522 pParseQueue
->bMflag
= false;
1525 void Export::SetChildWithText()
1527 if ( aResStack
.size() > 1 ) {
1528 for ( size_t i
= 0; i
< aResStack
.size() - 1; i
++ ) {
1529 aResStack
[ i
]->bChildWithText
= sal_True
;
1534 void ParserQueue::Push( const QueueEntry
& aEntry
)
1536 sal_Int32 nLen
= aEntry
.sLine
.getLength();
1539 aQueueCur
->push( aEntry
);
1540 if( nLen
> 1 && aEntry
.sLine
[nLen
-1] == '\n' )
1542 else if ( aEntry
.nTyp
!= IGNOREDTOKENS
){
1543 if( nLen
> 1 && ( aEntry
.sLine
[nLen
-1] == '\\') ){
1548 bCurrentIsM
= false;
1553 aQueueNext
->push( aEntry
);
1554 if( nLen
> 1 && aEntry
.sLine
[nLen
-1] != '\n' ){
1555 if( nLen
> 1 && ( aEntry
.sLine
[nLen
-1] == '\\') ){
1563 }else if( nLen
> 2 && aEntry
.sLine
[nLen
-1] == '\n' ){
1564 if( aEntry
.nTyp
!= IGNOREDTOKENS
){
1565 if( nLen
> 2 && ( aEntry
.sLine
[nLen
-2] == '\\') ){
1576 bLastWasM
= bCurrentIsM
;
1578 bCurrentIsM
= bNextIsM
;
1580 aQueueCur
= aQueueNext
;
1588 bLastWasM
= bCurrentIsM
;
1590 bCurrentIsM
= bNextIsM
;
1592 aQueueCur
= aQueueNext
;
1598 void ParserQueue::Close(){
1602 bLastWasM
= bCurrentIsM
;
1603 bCurrentIsM
= bNextIsM
;
1605 aQueueCur
= aQueueNext
;
1611 void ParserQueue::Pop( std::queue
<QueueEntry
>& aQueue
)
1613 while (!aQueue
.empty())
1615 QueueEntry aEntry
= aQueue
.front();
1617 aExport
.Execute(aEntry
.nTyp
, aEntry
.sLine
.getStr());
1621 ParserQueue::ParserQueue( Export
& aExportObj
)
1623 bCurrentIsM( false ),
1627 aExport( aExportObj
) ,
1630 aQueueNext
= new std::queue
<QueueEntry
>;
1631 aQueueCur
= new std::queue
<QueueEntry
>;
1635 ParserQueue::~ParserQueue(){
1636 if( aQueueNext
) delete aQueueNext
;
1637 if( aQueueCur
) delete aQueueCur
;
1640 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */